Gre*_*een 3 php design-patterns decorator
这本书说:
装饰器模式可用于扩展(装饰)某个对象的功能
我有一只兔子动物.我希望我的兔子能够拥有爬行动物的皮肤.只是想用爬行动物的皮肤装饰一只普通的兔子.
我有代码.首先,我有一个抽象的类Animal,每个都是任何动物共有的:
abstract class Animal {
abstract public function setSleep($hours);
abstract public function setEat($food);
abstract public function getSkinType();
/* and more methods which for sure will be implemented in any concrete animal */
}
Run Code Online (Sandbox Code Playgroud)
我为我的兔子创建课程:
class Rabbit extends Animal {
private $rest;
private $stomach;
private $skinType = "hair";
public function setSleep($hours) {
$this->rest = $hours;
}
public function setFood($food) {
$this->stomach = $food;
}
public function getSkinType() {
return $this->$skinType;
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止一切正常.然后我创建AnimalDecorator扩展的抽象类Animal:
abstract class AnimalDecorator extends Animal {
protected $animal;
public function __construct(Animal $animal) {
$this->animal = $animal;
}
}
Run Code Online (Sandbox Code Playgroud)
而这里的问题来了.注意AnimalDecorator也从Animal类中获取所有抽象方法(在这个例子中只有两个但实际上可以有更多).
然后我创建了ReptileSkinDecorator扩展的具体类AnimalDecorator.它也有两个相同的抽象方法Animal:
class ReptileSkinDecorator extends AnimalDecorator {
public function getSkinColor() {
$skin = $this->animal->getSkinType();
$skin = "reptile";
return $skin;
}
}
Run Code Online (Sandbox Code Playgroud)
最后我想用爬行动物的皮肤装饰我的兔子:
$reptileSkinRabbit = ReptileSkinDecorator(new Rabbit());
Run Code Online (Sandbox Code Playgroud)
但是我不能这样做,因为我在ReptileSkinDecorator课堂上有两个抽象的方法.他们是:
abstract public function setSleep($hours);
abstract public function setEat($food);
Run Code Online (Sandbox Code Playgroud)
所以,不仅仅是重新装饰皮肤,我还必须重新装饰setSleep()和setEat();方法.但我不需要.
在所有书中的例子中,Animal课堂上总是只有一个抽象方法.当然,它的工作原理.但是在这里我只是制作了一个非常简单的现实生活示例,并尝试使用Decorator模式,如果没有在ReptileSkinDecorator类中实现这些抽象方法,它就无法工作.
这意味着,如果我想使用我的例子,我必须创建一个全新的兔子,并为它自己setSleep()和setEat()方法实现它.好的,就这样吧.但是这个全新的兔子有Rabbit我传给的commont实例ReptileSkinDecorator:
$reptileSkinRabbit = ReptileSkinDecorator(new Rabbit());
Run Code Online (Sandbox Code Playgroud)
我在reptileSkinRabbit实例中有一个常见的兔子实例和自己的方法,而这个实例又有自己的reptileSkinRabbit方法.我有兔子兔子.但我认为我没有这种可能性.
我不理解Decarator模式的正确方法.在我对这种模式的理解中,请你指出我的例子中的任何错误.
谢谢.
我不知道我是否完全理解你的问题.这就是我读它的方式:
你的装饰师尚未完成.如它所示,它仍然是抽象的和不完整的:
abstract class AnimalDecorator extends Animal {
protected $animal;
public function __construct(Animal $animal) {
$this->animal = $animal;
}
}
Run Code Online (Sandbox Code Playgroud)
如果你想让它变得容易起作用,你也应该装饰所有方法,所以当你从中扩展时你不需要这样做AnimalDecorator.这里有许多方法中的两个示例:
abstract class AnimalDecorator extends Animal {
...
public function getSkinColor() {
return $this->animal->getSkinColor();
}
public function setSleep($hours) {
$this->animal->setSleep($hours);
}
...
Run Code Online (Sandbox Code Playgroud)
在委派了所有方法之后,您可以像以前一样覆盖混凝土装饰器中的那些方法:
class ReptileSkinDecorator extends AnimalDecorator {
public function getSkinColor() {
return "reptile";
}
}
Run Code Online (Sandbox Code Playgroud)
听起来你正试图强迫使用不适合问题的特定模式.装饰者通常聚集一些额外的东西(向头发添加辫子),而不是完全改变它,就像你试图用皮肤(头发到鳞片).
一个Builder模式,(其中指定如何你想建立的对象)可以适应问题更好.在你的情况下,你想要建立一个用爬行动物皮肤建造的兔子.(我来自哪里,而不是爬行动物的皮肤,制作一只有角的兔子并称之为jackalope :) 会很有趣 :)
我认为在这里使用Builder(或任何模式)可能实际上是矫枉过正.你是否必须使用这种特殊问题的模式?如何定义代码如下并暂时保留模式:
class Animal {
private $rest;
private $stomach;
private $skinType;
public function setSleep($hours) {
$this->rest = $hours;
}
public function setFood($food) {
$this->stomach = $food;
}
public function setSkinType($skin) {
$this->skinType = $skin;
}
// define the other getters too
public function getSkinType() {
return $this->$skinType;
}
}
class Rabbit extends Animal {
public function __construct() {
$this->rest = "rabbitRest"; // put whatever a rabbit rest is
$this->stomach = "rabbitStomach"; // put whatever a rabbit stomach is
$this->skinType = "hair";
}
}
Run Code Online (Sandbox Code Playgroud)
免责声明:我是一个c ++人,我的PHP非常糟糕,我确信这个代码有几个问题,但我希望你能得到这个想法.
所以兔子只会扩展一个Animal并相应地设置它的属性.然后,如果有人想要一个RabbitReptile,他们可以扩展Rabbit(可能是矫枉过正)或者只是制作一个兔子并相应地设置皮肤类型.