Ich habe eine Frage, die eher eine Designfrage ist. Ich habe eine Klasse, die eine Reihe von Funktionen definiert. Ich möchte jedoch, dass das Verhalten einiger Funktionen während der Laufzeit veränderbar ist - oder zumindest während der Entwurfszeit wie eine Plugin-Schnittstelle funktioniert. zB:Polymorph/Plugable PHP Klassen
class MyClass {
public function doSomething();
}
$obj = new MyClass();
// PSEUDO CODE
$obj->doSomething = doSomethingElse;
$obj->doSomething(); // does something else
Ich hatte verschiedene Ideen, wie man sowas in "echtem" Code umsetzen kann. Ich bin mir jedoch nicht ganz sicher, welches der richtige Weg ist. Ich dachte zuerst, ich könnte ein Interface für diesen Zweck verwenden.
interface IDoSomethingInterface {
public function doSomething();
}
class DoSomethingClass implements IDoSomethingInterface
{
public function doSomething()
{
// I do something!
}
}
class DoSomethingElseClass implements IDoSomethingInterface
{
public function doSomething()
{
// I actually do something else!
}
}
class MyClass {
public doSomething(IDoSomething $doSomethingProvider)
{
$doSomethingProvider->doSomething();
}
}
$obj = new MyClass();
$doSomethingProvider = new DoSomethingClass();
$doSomethingElseProvider = new DoSomethingElseClass();
$obj->doSomething($doSomethingProvider); // I do something!
$obj->doSomething($doSomethingElseProvider); // I do something else!
Dieser Ansatz könnte erweitert werden, nicht den doSomething Anbieter als Parameter übergeben haben, aber es entweder als Objekt Mitglied oder sogar Klassenmitglied einzustellen. Allerdings mochte ich nicht, dass ich eine Instanz von n-Klasse erstellen muss, die nicht einmal eine einzelne Elementvariable enthält, und die einzige Methode könnte einfach eine statische Klassenfunktion sein. An diesem Punkt brauchen wir kein Objekt. Ich wollte dann versuchen, Funktionsvariablen zu verwenden - aber ich würde dann aus OOP herausfallen, was ich auch nicht mochte. Meine Fragen sind: Was ist der beste Weg, um ein System wie ich beschrieben zu implementieren? Welchen Ansatz würden Sie verwenden? Ist etwas offensichtlich, an das ich vielleicht nicht gedacht hätte? Oder sollte ich einfach mit dem Interface-Ansatz gehen und mein schlechtes Gefühl, "körperlose" Objekte zu installieren, ist nur eine nerdige Kostbarkeit ?! Ich bin neugierig auf deine Antworten!
Edit:
Weil ich wirklich interessiert bin zu klären, ob dies tatsächlich ist (oder sein soll) ein Staat oder ein Strategy-Muster, ich werde über die Umsetzung in etwas mehr Detail gehen. Ich habe eine Basisklasse von Sammlungen, aus denen ich verschiedene spezifische Implementierungen ableite. Ich möchte in die Lage, ein einzelnes Element aus jeder spezifischen Implementierung wählen - aber ich will dynamisch können, ändern, wie dieses Element aus der Sammlung ausgewählt, zB:
class MyCollection implements Countable, ArrayAcces, Iterator
{
// Collection Implementation
public function select(ISelectionStrategy $strategy)
{
return $strategy->select($this);
}
}
interface ISelectionStrategy
{
public function select(MyCollection $collection);
}
class AlphaSelectionStrategy implements ISelectionStrategy
{
public function select(MyCollection $collection);
{
reset($collection);
if (current($collection))
return current($collection);
else
return null;
}
}
class OmegaSelectionStrategy implements ISelectionStrategy
{
public function select(MyCollection $collection)
{
end($collection);
if (current($collection))
return current($collection)
else
return null;
}
}
class RandomSelectionStrategy implements ISelectionStrategy
{
public function select(MyCollection $collection)
{
if (!count($collection))
return null;
$rand = rand(0, count($collection)-1);
reset($collection);
while($rand-- > 0)
{
next($collection);
}
return current($collection);
}
}
$collection = new MyCollection();
$randomStrategy = new RandomSelectionStrategy();
$alphaStrategy = new AlphaSelectionStrategy();
$omegaStrategy = new OmegaSelectionStrategy();
$collection->select($alphaStrategy); // return first element, or null if none
$collection->select($omegaStrategy); // return last element, or null if none
$collection->select($randomStrategy); // return random element, or null if none
Dies ist im Grunde, was ich will erreichen . Ist dies nun eher eine Strategie Musterimplementierung oder das Zustandsmuster - obwohl ich den Begriff Strategie verwendet habe, weil es in diesem Fall sowieso mehr passt. Soweit ich das verstehe, ist die Strategie und das Grundmuster grundsätzlich gleich, außer dass ihre Absicht anders ist. Der von Gordon angegebene Link besagt, dass die Absicht eines Zustandsmusters lautet "Einem Objekt erlauben, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert" - aber dies ist hier nicht der Fall. Ich möchte meiner MyCollection-Klasse sagen können, "benutze diesen oder jenen Algorithmus, um mir ein Element zu geben" - nicht "gib mir ein Element, das einen Algorithmus verwendet, den du durch deinen eigenen Zustand bestimmst". Hoffe jemand kann das klären!
Mit freundlichen Grüßen, Daniel
+1, Dieser Smiley wird das Ende von mir sein. xP –
Nun, du hast deine Frage schon selbst beantwortet. Sie möchten keine Staaten verwalten. Sie möchten einzelne Verhaltensweisen austauschen, daher ist Strategie angemessen. Auf einer Nebenbemerkung, da Sie scheinen, deutsch zu sein, kann ich das Buch phpdesignpatterns.de empfehlen – Gordon