Ich habe eine Klasse, zu der ich ständig hinzufügen.Eine Klasse folgen OCP - Factoring-Funktionen in Objekte
Es ist mir aufgefallen, dass diese Klasse nicht Open-Closed ist, weil all diese neuen Features hinzugefügt werden. Also dachte ich über das Schließen dieser Klasse gegen diese Änderung nach, indem ich diese Funktionen in Request-Objekte einkapselte. Ich am Ende mit etwas wie:
public abstract class RequestBase{}
public class AddRequest : RequestBase{}
etc...
public class OrderRepository{
public void ProcessRequest(RequestBase request){}
}
Das macht OrderRepository offen für Erweiterungen und geschlossen für Änderungen. Jedoch lief ich schnell in ein paar Probleme mit diesem:
1.) Die Daten die diese Anfrage benötigt, um zu arbeiten ist sowohl vom Benutzer zur Verfügung gestellt (Laufzeit) und Abhängigkeitsinjektion geliefert. Ich kann offensichtlich nicht beide mit einem Konstruktor zufriedenstellen. Ich kann nicht tun:
public class AddRequest{
public AddRequest(IEnumerable<Order> orders, int UserSuppliedContextArg1, DependencyInjectionArg1, DependencyInjectionArg2);
}
und rufen Sie das. Ich würde einen Weg für den DI-Rahmen haben wollen, um ein Objekt für mich "teilweise" zu konstruieren, und lass mich den Rest machen. Ich sehe jedoch keinen Weg, dies zu tun. Ich sah einen Blog, der dieses Konzept "variable Konstruktorinjektion" nannte.
2.) Das nächste, worüber ich nachdachte, war, dieses in zwei separate Klassen aufzuteilen. Der Benutzer würde einen RequestContext erstellen und füllen und ihn dann an das Repository übergeben, wodurch ein RequestProcessor (kann sich keinen besseren Namen vorstellen) daraus erstellt wird. Ich dachte darüber nach:
public abstract class RequestContextBase<T> where T : RequestProcessorBase{}
public class AddRequestContext : RequestContextBase<AddRequestProcessor>
public class OrderRepository{
public void ProcessRequest<T>(RequestBase<T> request){
var requestProcessor = IoC.Create<T>();
}
}
und das war ein guter erster Schritt. Der Anforderungsprozessor benötigt jedoch den genauen Kontexttyp, den er speichert, den ich hier nicht habe. Ich könnte ein Wörterbuch der Typen Typen verwenden, aber das Niederlagen der Zweck des Open-Closed .So ist ich am Ende mit etwas wie zu tun:
public class RequestProcessorBase<TRequestContext, TRequestProcessorBase> where TRequestContext : RequestContextBase<TRequestProcessorBase>
Das ist seltsam, und ich bin in der Regel nicht gern die curiously recurring template pattern. Außerdem erscheint mir die Vorstellung, dass der Benutzer einen Kontext füllt und mich darum bittet, eine Anfrage zu stellen, seltsam, obwohl das nur ein Problem mit der Namensgebung sein könnte.
3.) dachte ich über das Erhalten von allen oben genannten befreien und nur mit:
public AddRequest{
public AddRequest(DependencyInjectionArg1, DependencyInjectionArg2, ...){}
public void PackArgs(UserSuppliedContextArg1, UserSuppliedContextArg2, UserSuppliedContextArg3, ...){}
}
die nicht schlecht ist, aber die API ist hässlich. Nun müssen die Clients dieses Objekts es gleichsam "konstruieren". Und wenn sie vergessen, PackArgs aufzurufen, muss ich eine Ausnahme auslösen.
Ich könnte weitermachen, aber das sind die verwirrendsten Probleme, die ich im Moment habe. Irgendwelche Ideen?
Dies sieht etwas nützlich, aber meine Frage ist mehr über das Kapseln von Anfragen, nicht Abfragen. Außerdem greife ich nicht hinter dem Repository auf eine Datenbank zu, obwohl das wahrscheinlich keine Rolle spielt. – DavidN