Frage

Ich habe ein gemeinsames Szenario, in dem ich ein Objekt habe (a), das ein anderes Objekt logischerweise beeinflusst (b), wie A eine Notiz zu B oder A als deaktiviert (normalerweise ist A ein Benutzerobjekt des Systems, und B ist einige Art von Geschäftsobjekt wie ein Kunde oder ein Termin).

In der Vergangenheit befand sich die Methode auf dem betroffenen Objekt wie:

customer.Disable(user); // user is marking the customer as disabled

... aber es liest nicht gut (es erscheint rückwärts). Das Gegenteil:

user.Disable(customer);

... liest besser, aber es gibt etwas, das ich nicht auf den Finger setzen kann, das einfach nicht richtig scheint. Die einzige andere Möglichkeit ist, einen statischen Vermittler zu haben:

ThirdPartyClass.DisableCustomer(customer, user);

... aber die Domänenobjekte werden am Ende mehr zu DTOs und ich bevorzuge den Domain -Modellansatz, weil es sinnvoller ist.

Die Frage ist also: Was macht am sinnvollsten? Gibt es eine Option, die ich nicht in Betracht gezogen habe? Wer besitzt tatsächlich eine Operation wie diese?

Bearbeiten

Mit der zweiten Option werden die umsetzbaren Objekte des Systems (normalerweise) (normalerweise) riesig, da die Benutzer des Systems diejenigen sind, die alles so gut wie alles tun und beeinflussen.

War es hilfreich?

Lösung

Wie wäre es mit

customer.SetDisabledBy(user);

oder wenn Sie C# 4.0 oder eine andere Sprache mit ähnlichen Funktionen verwenden:

customer.SetDisabled(by: user);

Oder wenn Sie C# 3.5 oder neuer verwenden, können Sie Folgendes schreiben:

user.DisableCustomer(customer);

Während die Behinderungspflichtmethode eine Erweiterungsmethode in einer Klasse sitzt, die genannt wird CustomerActions das sitzt zusammen mit dem Customer Klasse. Auf diese Weise, wenn du bist using das Customer Namespace, User wird diese Erweiterungsmethode haben. Wenn du nicht bist using Es ist weg. User ist kein Gott -Objekt mehr, aber die Vermittlerklasse ist nirgends im Code zu finden. Sie könnten auch eine haben OrderActions Klasse, der bereitstellen wird user.CancelOrder(order), etc.

Gute Frage, habe mich zum Nachdenken gebracht!

Andere Tipps

user.Disable(customer) Fast scheint es das zu sagen user wird deaktiviert, seitdem user.Disable() Würde so lesen, als würde es auf den Benutzer handeln, nicht auf den Kunden.

user.DisableCustomer(customer) Lese ein bisschen besser, denke ich, da es klar macht, dass der Kunde behindert ist. Es bedeutet auch, dass Sie keine zusätzliche Klasse nur aus Gründen des Himmels benötigen.

Wenn Ihre Benutzerobjekte so viele Verantwortung übernehmen, dass es sich anfühlt, als hätten sie Methoden "Benutzer. Möglicherweise fühlen Sie sich besser, indem Sie entweder Schnittstellen verwenden, um die Rollen des Benutzers in domänenspezifische Stücke zu zerlegen, oder um Komposition zu verwenden, um dasselbe zu tun.

Schnittstellen

Sie haben eine IcustomerController -Oberfläche, die Benutzer implementiert. Wenn Sie die Benutzer benötigen, um Kunden zu deaktivieren, geben Sie den Kunden in ein icustomerControl und können ICC.DisableCustomer (Kunde) verwenden. Dies bietet eine natürliche Move -Lesart, da der Kunde nicht von einem Benutzer manipuliert wird, sondern von "etwas, das Kunden manipuliert".

Es lässt Sie auch flexibler, Dinge, die keine Benutzer sind, bei Bedarf keine Benutzer aktualisieren zu lassen.

Komposition

Nur eine Erweiterung der letzten Idee: Anstatt Icustomercontroller (IS-A) zu Benutzern, würden sie einen Icustomercontroller (HAS-A) besitzen. Jetzt liest der Anruf als user.customercontroller.disable (Kunde). Dies macht wiederum deutlich, dass Benutzer in einer bestimmten Eigenschaft (um Kunden zu betreffen) und nur gegen diese eine Domäne von Objekten (Kunden) zu handeln.

Sie hatten dieses Problem nicht erwähnt, aber eine Methode wie user.disable () könnte irgendetwas zu beeinflussen, selbst den Benutzer selbst. Einer der oben genannten korrigiert das.

Wenn Sie darauf hinweisen, dass viele Methoden in der Benutzerklasse haben Gott Objekt Anti-Muster. Es scheint, dass das Problem eine Kapselung ist, sodass der Datenfluss fließt

Der Benutzer führt eine Aktion auf einer Entität aus

kann neu interpretiert werden als

Der Befehl systemausführen auf Entität unter Bezugnahme auf den Benutzer

Dies würde ein Design bedeuten, das mit einem Befehlsmuster mit einem typischen Befehl wie folgt bevorzugt wird:

public class DisableCustomerCommand implements EntityCommand<Customer,User> {

  // This is the single EntityCommand templated method
  public Customer execute(Customer customer, User user) {
    customer.setEnabled(false);

    // TODO Add in audit code for User object

    return customer;
  }
}

Dies folgt dem allgemeinen OOD -Prinzip der Erstellung von körnigen einfachen Objekten, die sehr wenig tun, aber es gut machen.

Bearbeiten

Ich sollte darauf hinweisen, dass dies eine Überverfolgung ist. In der Regel müsste die Deaktivierung eines Kunden mehrere andere Felder erfordern, um zu ändern. Dies führt auch zu anämischen Einheiten (der Kunde wäre nur ein Haufen Getter/Setter), aber manchmal kann dies ein einfacheres Gesamtdesign sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
scroll top