2010-02-03 19 views
6

Um ein Beispiel zu zeigen, was ist diese Frage zu:Wohin mit Methoden, die von mehreren Klassen verwendet werden?

Ich habe derzeit ein Dilemma in PHP-Projekt, an dem ich arbeite. Ich denke an eine Methode, die von mehreren Klassen (UIs in diesem Fall - MVC-Modell) verwendet wird, aber ich bin mir nicht sicher, wie solche Methoden im OO-Design dargestellt werden. Das erste, was mir in den Sinn kam, war eine Klasse mit statischen Funktionen zu erstellen, die ich aufrufen würde, wenn ich sie brauche. Ich bin mir jedoch nicht sicher, ob es richtig ist.

genauer sein, möchte ich zum Beispiel arbeiten, mit der Zeit. Also brauche ich mehrere Methoden, die mit der Zeit umgehen. Ich dachte über das Erstellen einer Zeit-Klasse, wo ich Funktionen wäre, die überprüfen, ob die Zeit im richtigen Format etc.

Einige könnten sagen, dass ich Klasse überhaupt nicht für diese verwenden sollte, da in PHP kann ich noch verwende prozeduralen Code. Aber ich bin mehr an einer Antwort interessiert, die mich aufklären würde, wie man sich solchen Situationen in OOP/OOD nähert.

So sind die eigentlichen Fragen sind: Wie solche Verfahren zu vertreten? Ist der statische Funktionsansatz gut genug oder sollte ich etwas anderes überdenken?

+0

Sie sollten nur einen Vererbungsansatz verwenden, wenn die Klassen durch eine IS_A-Beziehung verknüpft sind. Ansonsten benutze ein Modul. –

Antwort

5

Ich würde empfehlen, eine normale Klasse erstellen die dieses Verhalten enthält, und dann diese Klasse lassen eine Schnittstelle aus der Klasse der Mitglieder extrahiert implementieren. Wenn Sie diese Methoden aufrufen müssen, injizieren Sie die Schnittstelle (nicht die konkrete Klasse) in den Verbraucher. Dadurch können Sie die beiden unabhängig voneinander variieren.

Dies mag mehr Arbeit klingen, aber ist einfach die Strategy Design angewandt Muster.

Dies wird es auch wesentlich einfacher machen, den Code zu testen, weil der Code lockerer gekoppelt ist.


Hier ist ein Beispiel in C#.

Schnittstelle:

public interface ITimeMachine 
{ 
    IStopwatch CreateStopwatch(); 

    DateTimeOffset GetNow(); 
} 

Produktion Umsetzung:

public class RealTimeMachine : ITimeMachine 
{ 
    #region ITimeMachine Members 

    public IStopwatch CreateStopwatch() 
    { 
     return new StopwatchAdapter(); 
    } 

    public DateTimeOffset GetNow() 
    { 
     return DateTimeOffset.Now; 
    } 

    #endregion 
} 

und hier ist ein Verbraucher der Schnittstelle:

public abstract class PerformanceRecordingSession : IDisposable 
{ 
    private readonly IStopwatch watch; 

    protected PerformanceRecordingSession(ITimeMachine timeMachine) 
    { 
     if (timeMachine == null) 
     { 
      throw new ArgumentNullException("timeMachine"); 
     }   

     this.watch = timeMachine.CreateStopwatch(); 
     this.watch.Start(); 
    } 

    public abstract void Record(long elapsedTicks); 

    public virtual void StopRecording() 
    { 
     this.watch.Stop(); 
     this.Record(this.watch.ElapsedTicks); 
    } 
} 
+0

Das bedeutet, ich sollte eine Klasse für die Behandlung von benutzerdefinierten Funktionen + Klasse für jede dieser Funktionen erstellen und dann einfach nur ausführen execute()? So würde beispielsweise die Funktion "timeToString" mit der Funktion execute(), die die Schnittstelle implementiert, zu einer separaten Klasse werden. Und ich würde es durch neue CustomFunction (neue TimeToString) nennen; ... $ custom_function-> ausführen()? Funktioniert das Strategiemuster oder missverstehe ich das Konzept? Ist es nicht ein bisschen übertrieben, für jede einzelne Funktion eine Klasse zu erstellen? –

+0

Sie müssen für jede Funktion keine Klasse erstellen. Sie können verwandte Vorgänge in einer einzigen Klasse bündeln. Darum geht es schließlich bei Verkapselung und Kohäsion. Diese Operationen können alle auf derselben Schnittstelle definiert werden, so dass Sie in einem Bündel eine zusammenhängende Menge von Operationen durchführen können. –

+0

Könnten Sie bitte Ihren Beitrag mit einem kurzen Beispiel (in einer beliebigen Sprache) bearbeiten? Wie ich das immer noch nicht verstehe. Soll ich einfach eine Klasse mit mehreren Funktionen erstellen, eine von den Mitgliedern extrahierte Schnittstelle implementieren und dann diese Schnittstelle dort einspeisen, wo ich sie brauche und alle Funktionen aufrufen? Ich denke, was mich verwirrt ist, dass Sie das Strategie-Muster erwähnt haben und ich versuche, die Lösungen genau dadurch zu implementieren. Ich verstehe auch nicht, warum ich eine Schnittstelle haben würde, die von nur einer Klasse implementiert wird. Nur um enge Verbindungen zu vermeiden, indem man Betonklasse nennt? –

0

Verwenden Sie eine Klasse als Namespace. Also ja, habe eine statische Klasse.

+3

Statische Klasse = enge Kopplung –

+0

@Seemann, ich bevorzuge einfache "richtige" und "richtige" Lösungen (ja, ich bin manchmal etwas heuchlerisch ...). Wenn ich später eine "normale" Klasse erstellen muss, kann ich den Code dafür leicht umgestalten. Sonst ist es verschwendete Zeit, IMO. – strager

0

Ich mache kein PHP, aber von einem OO Standpunkt, diese Art von Dienstprogramm Methoden als statische Methoden zu platzieren, ist in Ordnung. Wenn sie vollständig wiederverwendbar sind, sollten Sie sie in eine Klasse von utils aufnehmen.

+1

Statische Klasse = enge Kopplung –

+0

Nicht, dass ich IoC/dep inj nicht schätze, aber in diesem Fall, wo eine Methode etwas so Einfaches und nicht Erweiterbares wie Zeit behandelt, scheint mir eine andere Ebene der Indirektionierung überdimensioniert zu sein . – spender

+2

Die Zeit ist weder geradlinig noch nicht erweiterbar. Beim Testen von Einheiten ist es oft sehr wichtig, dass Sie simulieren können, dass die 'aktuelle' Zeit viele verschiedene Werte innerhalb von Millisekunden voneinander hat. –

1

Obwohl Sie sagen, dass Sie eine Struktur wollen für beliebige, nicht zusammenhängenden Aufgaben , haben Sie ein Beispiel für eine Zeitklasse angegeben, die viele verwandte Funktionen hat. Aus OO-Sicht würden Sie also eine Time-Klasse erstellen und beispielsweise eine statische Funktion getCurrentTime() haben, die eine Instanz dieser Klasse zurückgibt. Oder Sie können definieren, dass das Standardverhalten der Konstruktoren die aktuelle Zeit zurückgibt, je nachdem, was Sie mehr möchten. Oder beides.

class DateTime { 

    public static function getNow() { 
     return new self(); 
    } 

    public function __construct() { 
     $this->setDateTime('now'); 
    } 

    public function setDateTime($value) { 
     #... 
    } 

} 

Aber abgesehen davon gibt es bereits ein builtin DateTime class in PHP.

Verwandte Themen