it-swarm.com.de

Ist das Definieren einer leeren Klasse zur Darstellung einer Domänenentität notwendigerweise ein Zeichen für ein schlechtes Architekturdesign?

Ich stehe derzeit vor folgendem Szenario:

  • Bei der Definition der Anforderungen meines Systems auf einem Blatt Papier habe ich zwei verschiedene Entitäten A und B beschrieben (z. B. Cat und Dog).
  • Nachdem sie aufgelistet hatten, was A und B tun sollten, hatten sie genau die gleichen Verhaltensanforderungen (z. B. das Verhalten eines Animal).
  • Um dies widerzuspiegeln, habe ich A und B als Klassen implementiert und beide von C geerbt (z. B. die abstrakte Klasse Animal).

Sollten A und B als Klassen beibehalten werden oder sollten sie vollständig aus der Architektur entfernt werden, wobei nur C beibehalten wird? Ist dies ein Zeichen für ein Problem in der Architektur dieser Lösung?


Beispiel:

Angenommen, ich implementiere ein Tierhandlungssystem und habe die folgenden Anforderungen:

  • Meine Tierhandlung kann Katzen und Hunde pflegen
  • Wenn eine Katze gepflegt wird, sollte die Anzahl der toten Pelze Null sein
  • Wenn ein Hund gepflegt wird, sollte die Anzahl der toten Pelze Null sein

Um dieses Problem zu lösen, implementiere ich die folgenden Tests:

[Test]
public void When_DogIsGroomed_Should_DeadFurCountBeZero()
{
    PetShop petShop = new PetShop();
    Dog dog = new Dog();
    petShop.Groom(dog);
    Assert.AreEqual(0, dog.DeadFurCount);
}

[Test]
public void When_CatIsGroomed_Should_DeadFurCountBeZero()
{
    PetShop petShop = new PetShop();
    Cat cat = new Cat();
    petShop.Groom(cat);
    Assert.AreEqual(0, cat.DeadFurCount);
}

Mit folgendem Implementierungscode:

public abstract class Animal()
{
    public int DeadFurCount { get; private set; }

    internal void Groom()
    {
        this.DeadFurCount = 0;
    }
}
public class PetShop()
{
    public void Groom(Animal animal)
    {
        animal.Groom();
    }
}
public class Dog(): Animal
{

}
public class Cat(): Animal
{

}

In diesem Beispiel sollten Cat und Dog entfernt werden und somit nur bei Animal für die endgültige Lösungsarchitektur verbleiben? Sind diese leeren Klassen ein schlechtes Zeichen oder Design? ?

Eine Sache, die ich beim Entfernen befürchte, ist, dass meine Tests weniger repräsentativ für das System sind, das ich implementiere. Schließlich sprechen meine Anforderungen von Hunden und Katzen, nicht von Tieren. Gleichzeitig riechen leere Klassen normalerweise.

4
Albuquerque

Schließlich sprechen meine Anforderungen von Hunden und Katzen, nicht von Tieren. Gleichzeitig riechen leere Klassen normalerweise.

Besprechen Sie mit Ihren Domain-Experten, warum sie die Wörter "Hund" und "Katze" anstelle eines allgemeineren Wortes wie "Tier" oder "Haustier" verwenden. Ich kann mir einige mögliche Ergebnisse vorstellen:

  • Hunde und Katzen werden in Ihrer Domäne genau gleich behandelt : Vereinfachen Sie Ihren Wortschatz und verwenden Sie einen einzelnen Begriff (und damit eine einzelne Klasse).
  • Bestimmte Geschäftsregeln hängen von der Art des Tieres ab : Verwenden Sie eine einzelne Klasse und modellieren Sie die Art des Tieres als Aufzählung. Vererbung ist hier nicht die beste Lösung, da es wahrscheinlich nicht in der Verantwortung von Animal liegt, alle gegenwärtigen und zukünftigen Geschäftsregeln zu berücksichtigen.
  • Die Struktur von Hunden und Katzen hat etwas grundlegend anderes : Modellieren Sie sie als zwei separate Einheiten (möglicherweise mit einer gemeinsamen Oberklasse, wenn Sie eine gemeinsame Struktur benötigen).
14
casablanca

Nein, leere Klassen sind kein Geruch. Sie sind ein Zeichen dafür, dass Sie den Wert eines guten Namens kennen.

Genau das haben diese leeren Klassen vor. Das sind gute Namen. Ich erstelle leere Klassen, um Ausnahmen immer gute Namen zu geben.

Hund und Katze haben vielleicht eines Tages eine andere Pflegelogik, aber im Moment nicht. Das ist in Ordnung. Es wäre auch in Ordnung, diese Logik nach unten zu drücken, wenn Sie der Meinung wären, dass sich die Pflege mit größerer Wahrscheinlichkeit unabhängig ändert. Nur weil es jetzt dasselbe ist, heißt das nicht, dass Sie es an einem Ort tun müssen. Es ist in Ordnung, sowohl x als auch y zu haben, auch wenn beide auf 1 gesetzt sind.

Sie werden in Schwierigkeiten geraten, wenn Sie sich andere Tiere vorstellen, die eines Tages gepflegt werden könnten, und sie "nur für den Fall" hinzufügen. Das wird dich vom YAGNI-Stick schlagen lassen.

7
candied_orange

Ja, es ist ein Code-Geruch.

Wenn Sie leere Klassen ohne Logik haben, deutet dies darauf hin, dass Sie irgendwo in Ihrem Code eine bedingte Logik haben, die überprüft, welche Klasse eine Instanz ist.

z.B.

if(x is Dog) then y

Es könnte auch darauf hindeuten, dass Sie immer mehr leere Klassen haben, Katzen, Hunde, Kuh, Schafe usw. usw.

Diese Art von Dingen sollte normalerweise durch eine Enum- oder String-Eigenschaft "Type" für das übergeordnete Objekt ersetzt werden.

Natürlich muss ich die übliche Einschränkung hinzufügen. "Code Geruch"! = schlechter Code. Es ist nur etwas, das oft in Verbindung mit schlechtem Code gesehen wird.

Außerdem schlägt es mir vor, dass Sie einen OOP) Ansatz auf Geschäftsregeln anwenden, was nicht immer eine gute Idee ist.

Ihr Geschäftsbeispiel für die Tierpflege sollte keine Hunde- und Katzenobjekte mit einer Bräutigammethode enthalten. Ich würde erwarten, dass es eine Service Klasse ohne Methoden gibt.

Service
{
    Id;
    CustomerId
    Type;
    Price;
    Date;
    Status;
}

Ein Kunde würde einen Servicetyp = "Dog SuperGroom" buchen und Sie würden Klassen wie LateServiceEmailer haben, in denen Ihr OOP] in Kraft treten würde.

Kein Unternehmen möchte hören "Oh, wir können diese Änderung nicht vornehmen, weil ein Fish kein Tier ist.

2
Ewan

Der Quellcode hat eine interessante Perspektive (natürlich die für Menschen lesbare Form), die Sie berücksichtigen müssen!

Es ist die Abstraktion eines mentalen Prozesses! Dein mentaler Prozess. Der mentale Prozess, der versucht, eine konzeptuelle Repräsentation zu konstruieren, Ihre konzeptuelle Repräsentation. Ihre Interpretation eines Systems, eines Teils der Welt (dieser oder einer imaginären Welt).

Eine leere Klasse mit einem Namen ist nicht unbedingt ein Zeichen für schlechte Architektur. Es ist eher wie ein "Siegel" von Ihrer Architektur. Dies ist, was Sie beim Betrachten von Ihrer Domain gesehen haben.

Warum sind in der realen Welt nicht alle Autos weiß? Oder schwarz ... oder beige? Eine Eigenschaft (d. H. Farbe) für ein Objekt zu haben, wenn dies für die Funktionalität/Verwendung absolut keinen Unterschied macht meistens scheint ziemlich redundant zu sein. Aber Kunden sind oft bereit, sich darüber Gedanken zu machen, stolz darauf zu sein und es zu genießen (OK, natürlich nicht immer, aber Sie verstehen, worum es geht). Es macht ihr Leben besser, ohne wahrer technischer Wert (wieder in den meisten Fällen) hinzuzufügen. Das Beibehalten einer zusätzlichen Color -Eigenschaft in einer Autodatenbank ist nur ein weiterer Schmerz für den Entwickler. Sie vergrößert die Größe einer Datenbank, kommt und geht, führt keine zusätzliche Validierung ein usw.

Wenn Sie Code schreiben, müssen Sie die Unterscheidung berücksichtigen, was Auswirkungen auf das Design hat und was einfach der Vollständigkeit halber vorhanden ist.

Oh, und noch etwas. Du sagst:

In diesem Beispiel sollten Katze und Hund entfernt werden, um nur für die endgültige Architektur der Lösung bei Animal zu bleiben. Sind diese leeren Klassen ein schlechtes Zeichen oder Design?

Ja. Denken Sie daran, es ist immer noch heute! Nehmen Sie niemals die heutige Architektur für endgültig! Sie müssen sich fragen, wie hoch die Kosten für die Einführung dieser Klassen sind in einigen Monaten, insbesondere nachdem Sie eine relativ umfangreiche Codebasis erstellt, Abhängigkeiten verteilt und möglicherweise zahlreiche Annahmen durchlaufen haben? Was ist, wenn sich die Anforderungen ändern, wie sie es oft tun, geschweige denn auf "brechende" Weise?

Sie können also die Klassen dort behalten heute, um flexibel genug zu sein, um Änderungen zu berücksichtigen morgen. Veränderungen vorauszusehen und darauf vorbereitet zu sein, ist eines der Dinge, die einen guten Entwickler ausmachen. Und vergessen Sie natürlich nicht, dass es eine Kunst ist, ein gutes Gleichgewicht zwischen Über- und Unterentwicklung zu halten.

0
Vector Zita

Nehmen Sie ein anderes Beispiel, um den Punkt mit einer einfacheren Antwort zu veranschaulichen.

Ich habe 2 Messungen - HeightFromGroundInMeters und NumberOfPotatoes. Sie sind beide Verhaltenszahlen (sagen wir), jedoch sind sie semantisch völlig unabhängig und sicherlich nicht logisch austauschbar.

Ich würde sagen, dies war ein Beispiel für Klassen, die nützlich existieren (in dem Sinne, dass es klar genug ist, dass sie eindeutig zwei verschiedene Dinge darstellen und die logische Äquivalenz wahrscheinlich falsch ist), aber beide haben dieselben Verhaltenseigenschaften.

TLDR: Absolut legitim.

0
LoztInSpace