Laden...

Architekturfrage Farb-Tool

Erstellt von m0rius vor 14 Jahren Letzter Beitrag vor 14 Jahren 1.437 Views
m0rius Themenstarter:in
1.002 Beiträge seit 2007
vor 14 Jahren
Architekturfrage Farb-Tool

Hallo,

ich arbeite zur Zeit an einem Farb-Tool, das z.B. Webdesignern die einfache Arbeit mit Farben und die Farbwahl- bzw. Suche erleichtert.
Es sollen Methoden zur Konvertierung von Farben verschiedener Farbräume (RGB, HSV) zur Verfügung gestellt werden. Weiterhin soll es möglich sein, andere "Utilities" zu erstellen, beispielsweise zum Auffinden der Komplementärfarbe, zum Abdunkeln / Aufhellen einer Farbe usw. ...

Meine ersten Überlegungen sehen strukturmäßig wie folgt aus - gibt es dagegen etwas einzuwenden? Ich habe mich an der ToString()-Methode orientiert und dem IColor-Interface deshalb eine ToColor()-Methode hinzugefügt, bin mir aber nicht sicher.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

P
67 Beiträge seit 2008
vor 14 Jahren

Ein kleines Problem:
Interfaces in ein Struct zu implementieren kann zum Boxing des Value-Types (Deine Color-Struct werden als Referenz weitergegeben) führen und würde Perfomance-Buße einbringen... mehr dazu hier

Religionskriege sind Konflikte zwischen erwachsenen Menschen, bei denen es darum geht, wer den cooleren, imaginaeren Freund hat

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo m0rius,

gibt es dagegen etwas einzuwenden?

kann man schon so machen.

Ich frage mich allerdings, warum du bei HSV double, aber bei RGB ints benutzt. Ich würde in beiden Fällen für double plädieren, denn für RGB mit ints gibt es ja schon die Color-Struktur aus dem Framework.

Außerdem frage ich mich, warum du die Konvertierung asymmetrisch angelegt hast. Nach Color gibt es einen impliziten Cast wogegen es von Color nur die statischen Methoden von ColorConvert gibt.

herbivore

m0rius Themenstarter:in
1.002 Beiträge seit 2007
vor 14 Jahren

Hallo,

wenn die Performance die einzige Gefahr bzw. der einzige Nachteil an der Interface-Implementierung ist, dann stellt sie für mich kein signifikantes Problem dar.
Die Alternative wäre die Verwendung einer Klasse, was aber design-technisch nicht ganz sauber ist. Oder würde dieser Aufwand i.A. die Verwendung einer Klasse legitimieren, obwohl eine Farbe keine Identität besitzt?

Ich habe bei RGB Ganzzahlen verwendet, da im RGB-Farbraum Farben durch ganzzahlige Farbanteile repräsentiert werden, die Eigenschaften im HSV-Raum jedoch durch Gleitkommazahlen im Intervall [0,1].
Warum, herbivore, würdest du für double-Eigenschaften plädieren?

Die implizite Konvertierung nach Color habe ich eingefügt, da die Strukturen so recht einfach zu verwenden sind, wenn sie einer Eigenschaft zugewiesen werden, die eine Color-Struktur erwartet.
Damit die Strukturen nicht mit Konvertierungsmethoden überfüllt werden (Single Responsibility Principle), habe ich eine eigene Klasse für die Konvertierungszwecke erstellt. Mein Gedankengang war, dass ich auf diesem Weg beim Hinzufügen neuer Farbräume bzw. Darstellungsmöglichkeiten nicht die Farbklassen anfassen muss ...

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

0
767 Beiträge seit 2005
vor 14 Jahren

Würden in dem Fall die TypeConverter was bringen? Wenn man den registriert müsste man theoretisch mit


  System.Convert.ChangeType(color, typeof(HsvColor));

konvertieren können. Ich hab allerdings praktisch keine Erfahrung damit.

edit: Methodensignatur fixed.

loop:
btst #6,$bfe001
bne.s loop
rts

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo m0rius,

Warum, herbivore, würdest du für double-Eigenschaften plädieren?

zum Beispiel um Rundungsfehler bei der (wiederholten) Konvertierung von RGB in HSV und zurück sowie überhaupt beim Rechnen mit Farbwerten zu verringern.

Mal abgesehen davon, dass es rein willkürlich ist, HSV durch Gleitkommazahlen im Intervall [0,1] zu definieren und es auch andere Definitionen gibt, bei denen HSV als Integer (0-359, 0-100, 0-100) repräsentiert werden.

Wobei man natürlich auch zwischen internem Typ und dem Typ der Properties unterschieden könnte.

Mein Gedankengang war, dass ich auf diesem Weg beim Hinzufügen neuer Farbräume bzw. Darstellungsmöglichkeiten nicht die Farbklassen anfassen muss ...

Ok, da hast du natürlich Recht. Um den Preis einer sehr prozeduralen Herangehensweise. Aber einen Tod muss man sterben.

herbivore

P
67 Beiträge seit 2008
vor 14 Jahren

wenn die Performance die einzige Gefahr bzw. der einzige Nachteil an der Interface-Implementierung ist, dann stellt sie für mich kein signifikantes Problem dar.

Nein... die eigentliche Gefahr ensteht beim Boxing. Hast du dir den Link durchgelesen?

Damit die Strukturen nicht mit Konvertierungsmethoden überfüllt werden ( Single Responsibility Principle), habe ich eine eigene Klasse für die Konvertierungszwecke erstellt. Mein Gedankengang war, dass ich auf diesem Weg beim Hinzufügen neuer Farbräume bzw. Darstellungsmöglichkeiten nicht die Farbklassen anfassen muss ...

das mit dem SRP-Zeugs ist zwar richtig, (Cast-)Operatoren sollten da aber eine Ausnahme sein (Immerhin dienen sie ja zu erleichterung... nicht als direkte Methode).

Mein Vorschlag: lass das mit den Interfaces. Implementiert stattdessen in jeden Struct ein Operator um XColor -> System.Drawing.Color zu Casten und einen weiteren Operator um wieder zurück zu casten

Religionskriege sind Konflikte zwischen erwachsenen Menschen, bei denen es darum geht, wer den cooleren, imaginaeren Freund hat

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo pohlmann,

Hast du dir den Link durchgelesen?

auch wenn ich nicht m0rius bin, hab ich ihn (jetzt) gelesen. Also mich hat die Argumentation nicht überzeugt.

Es wird angekreidet, dass die Änderung an p in dem folgenden Code nicht auf employee durchschlägt.


IPromotion p = employee;
Console.WriteLine(employee);
p.promote();
Console.WriteLine(employee);

Und es wird gesagt, dass die Änderung durchschlagen würde, wenn Employee eine Klasse wäre. Aber wenn Employee absichtlich ein Werttyp ist, dann ist es nicht nur vollkommen korrekt sondern geradezu erwünscht, dass die Änderung nicht durchschlägt. Zum Vergleich folgender Code:


Employee e = employee;
Console.WriteLine(employee);
e.promote();
Console.WriteLine(employee);

Da schlägt die Änderung an e auch nicht auf employee durch und das ist ja auch gerade erwünscht. Die Bemerkung, dass die Änderung durchschlagen würde, wenn Employee eine Klasse wäre, wäre auch bei diesem Code zwar richtig, aber eben vollkommen irrelevant, wenn Employee absichtlich ein Werttyp ist.

Alles dreht sich also letztlich um die Frage, ob etwas konzeptionell ein Werttyp sein sollte oder nicht. Nur hat diese Frage nichts damit zu tun, ob ein Interface definiert wurde oder nicht.

Und bei der Aussage, dass Employee eine Klasse sein sollte, gebe ich dem Autor sogar Recht, weil Employee-Objekte ja eine Identität haben. Aber das liegt überhaupt nicht daran, dass ein Interface verwendet wurde.

herbivore

m0rius Themenstarter:in
1.002 Beiträge seit 2007
vor 14 Jahren

Hallo pohlmann,

ja, ich habe den Blogbeitrag gelesen. Allerdings hat mich das nicht überzeugt, die Strukturen aus diesem Grund in Klassen zumzuwandeln (s. Argumentation oben).

Hallo herbivore,

ich würde das Verhalten einer RgbColor-Struktur nicht erwarten, die nach außen ganzzahlige Eigenschaften R, G & B präsentiert, intern jedoch Fließkommazahlen speichert, sodass dadurch bei einer Konvertierung in den HSV-Farbraum möglicherweise ein anderes Ergebnis erzeugt wird, als es durch die ganzzahlige Variante geschehen würde!

Nun ja, ich finde die Herangehensweise einer Konvertierungsklasse auf diese Weise nicht so abwegig; ich habe mich da an die Convert-Klasse aus dem Framework angelehnt (daher auch nicht ColorConverter, wie ich es sonst genannt hätte).
Ich werde wahrscheinlich trotzdem die Konvertierungsklasse entfernen, da außer dem RGB- und dem HSV-Farbraum keine Unmengen an weiteren Farbräumen vorhanden sein werden.

Wie du sagst, einen Tod muss man sterben; allerdings wäre es bei der Verlagerung der Konvertierungsmethoden in die jeweilige Klasse sauberer, die Methoden dafür bereits im Interface IColor vorzuschreiben, oder? Schließlich soll jede Farbe, die IColor implementiert, in jede andere Darstellungsform gebracht werden können.

So, wie ich das auf der Grundlage eurer Argumentation verstehe, geht die ausschließliche Verwendung von Strukturen und den in ihnen enthaltenen Konvertierungsmethoden- und Operatoren den Boxingproblemen und OOP-Unreinheiten aus dem Weg, richtig?

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

P
67 Beiträge seit 2008
vor 14 Jahren

Und es wird gesagt, dass die Änderung durchschlagen würde, wenn Employee eine Klasse wäre. Aber wenn Employee absichtlich ein Werttyp ist, dann ist es nicht nur vollkommen korrekt sondern geradezu erwünscht, dass die Änderung nicht durchschlägt.

IPromotion employee = new Employee("Cool Guy", 65);
IPromotion employee2 = employee;
Console.WriteLine(employee2); // ausgabe: 65
employee.promote();
Console.WriteLine(employee2); // ausgabe: 66!!

Gz

Religionskriege sind Konflikte zwischen erwachsenen Menschen, bei denen es darum geht, wer den cooleren, imaginaeren Freund hat

m0rius Themenstarter:in
1.002 Beiträge seit 2007
vor 14 Jahren

Hallo pohlmann,

hier ist Employee als Klasse implementiert, nicht als Struktur.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo m0rius,

ich würde das Verhalten einer RgbColor-Struktur nicht erwarten, ...

Es ist doch aber nichts ungewöhnliches, dass bei Datentypen die interne Genauigkeit größer ist.

ich habe mich da an die Convert-Klasse aus dem Framework angelehnt :::

In Anlehnung an das Framework müsste die dann aber eigentlich ConvertColor heißen, damit der "Gag", dass sich der Methodenaufruf wie ein korrekter Satz liest (Convert.ToByte ==> convert to byte), erhalten bleibt. Oder noch besser müssten deine Methoden als Erweiterungsmethoden von Convert definiert sein (kann man eigentlich Klassen auch um statische Methoden erweitern?).

allerdings wäre es bei der Verlagerung der Konvertierungsmethoden in die jeweilige Klasse sauberer, die Methoden dafür bereits im Interface IColor vorzuschreiben, oder?

Mein Vorschlag war ja über beide Richtungen Casts zu verwenden.

So, wie ich das auf der Grundlage eurer Argumentation verstehe, geht die ausschließliche Verwendung von Strukturen und den in ihnen enthaltenen Konvertierungsmethoden- und Operatoren den Boxingproblemen und OOP-Unreinheiten aus dem Weg, richtig?

Die ausschließliche Verwendung von Strukturen ist ok. Den Schluss kann ich allerdings nicht nachvollziehen. Bei der Verwendung des Interfaces würde es schon weiterhin zu Boxing kommen. In meiner Argumentation oben ging es ja nur darum, dass die Verwendung von Boxing durchaus zum gewünschten Ergebnis führt. Vielleicht meinst du das.

hier ist Employee als Klasse implementiert, nicht als Struktur.

Nö, der Effekt in dem Beispiel von pohlmann tritt unabhängig davon auf, ob Employee eine Klasse oder eine Struktur ist.

Hallo pohlmann,

auch dein neues Beispiel kann man als korrektes Verhalten ansehen. Nach der Zuweisung des Werts an employee hat man - durch das Boxing - eine Referenz auf ein Objekt vom (statischen) Typ IPromotion, denn Variablen vom Typ eines Interfaces sind immer Referenzvariablen. Ein Interface kann zwar sowohl von einigen Strukturen als auch von einigen Klassen implementiert sein, aber in dem Moment wo man die Zuweisung von employee an employee2 macht, arbeitet man ja bereits ausschließlich auf der Ebene des Interfaces. Welchen Typ das Objekt in employee hat, ist nicht mehr (zwangsläufig) bekannt, interessiert nicht mehr bzw. darf im Grunde nicht mehr interessieren. Man darf bzw. muss davon ausgehen, dass man mit einer Referenz arbeitet.

Das ist aber nun auch wieder nichts spezielles, was durch das Interface entsteht, sondern einfach eine Eigenschaft des Boxings. Wenn überhaupt müsste man also das Boxing und nicht die Verwendung von Interfaces in Frage stellen.

herbivore

m0rius Themenstarter:in
1.002 Beiträge seit 2007
vor 14 Jahren

Hallo herbivore,

ich habe mich mit "ausschließlich" zu ungenau ausgedrückt, gemeint war die Verwendung von Strukturen ohne die Implementierung von Interfaces.

m0rius

Mein Blog: blog.mariusschulz.com
Hochwertige Malerarbeiten in Magdeburg und Umgebung: M'Decor, Ihr Maler für Magdeburg

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo m0rius,

ja, dann solltest du auf jeden Fall auf der sicheren Seite sein.

herbivore

T
381 Beiträge seit 2009
vor 14 Jahren

Die Convert methoden ins Interface zu packen würde bedeuten, dass das Interface alle seine Implementierungen kennt.

Ich würde daher die Convertierungsmethoden wohl wirklich in einer eigenen Klasse lassen.