Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/231.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 装饰图案中有什么这么有用?我的例子没有';行不通_Php_Design Patterns_Decorator - Fatal编程技术网

Php 装饰图案中有什么这么有用?我的例子没有';行不通

Php 装饰图案中有什么这么有用?我的例子没有';行不通,php,design-patterns,decorator,Php,Design Patterns,Decorator,书上说: decorator模式可用于扩展(装饰) 某个对象的功能 我有一只兔子。我希望我的兔子有爬行动物的皮肤。只想用爬行动物的皮肤装饰一只普通的兔子 我有密码。首先,我有一个抽象类Animal,它包含所有动物共有的东西: abstract class Animal { abstract public function setSleep($hours); abstract public function setEat($food); abstract public fu

书上说:

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 */
} 
我为我的兔子创建类:

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;
    }

}
到目前为止一切都还好。然后我创建了抽象的
AnimalDecorator
类,该类扩展了
Animal

abstract class AnimalDecorator extends Animal {
    protected $animal;

    public function __construct(Animal $animal) {
        $this->animal = $animal;
    }
}
class ReptileSkinDecorator extends AnimalDecorator {
    public function getSkinColor() {
        $skin = $this->animal->getSkinType();
        $skin = "reptile";
        return $skin;
    }
}
问题来了。请注意,
AnimalDecorator
还从
Animal
类中获取所有抽象方法(在本例中,只有两个,但在实际中可能有更多)

然后我创建了一个具体的
爬虫类动物生态学家
类,它扩展了
动物生态学家
。它还有来自
Animal
的两种相同的抽象方法:

abstract class AnimalDecorator extends Animal {
    protected $animal;

    public function __construct(Animal $animal) {
        $this->animal = $animal;
    }
}
class ReptileSkinDecorator extends AnimalDecorator {
    public function getSkinColor() {
        $skin = $this->animal->getSkinType();
        $skin = "reptile";
        return $skin;
    }
}
最后,我想用爬行动物皮装饰我的兔子:

$reptileSkinRabbit = ReptileSkinDecorator(new Rabbit());
但我不能这样做,因为我在
爬行动物类
类中有两个抽象方法。它们是:

abstract public function setSleep($hours);
abstract public function setEat($food);
因此,除了只重新装饰皮肤,我还必须重新装饰
setSleep()
setEat()方法。但我不需要

在所有的书籍示例中,
Animal
类中总是只有一个抽象方法。当然,这是可行的。但在这里,我只是制作了一个非常简单的实际示例,并尝试使用Decorator模式,如果没有在
爬行动物类
中实现这些抽象方法,它将无法工作

这意味着如果我想使用我的示例,我必须创建一个全新的rabbit,并为它实现自己的
setSleep()
setEat()
方法。好吧,随它去吧。但是,这个全新的兔子有一个commont
rabbit
的实例,我传递给了
爬行动物王国创造者

$reptileSkinRabbit = ReptileSkinDecorator(new Rabbit());
我有一个普通的rabbit实例,它在爬行动物kinrabbit实例中有自己的方法,而爬行动物kinrabbit实例又有自己的爬行动物kinrabbit方法。我有一只兔子。但我想我不必有这种可能性

我不能正确理解去角化器的模式。请你指出我的例子中的任何错误,在我对这个模式的理解中


谢谢。

装饰器模式必须将其基类或实现接口中定义的所有成员委托给它正在扩展的对象。换句话说,爬虫类动物创造者的setSleep、setEat和getSkinType方法必须调用兔子(或您选择用爬虫类皮肤装饰的任何其他动物后代)的setSleep和setEat方法

另外,我刚刚注意到,在您的示例中,您正在尝试更改Animal基类中定义的方法的使用(尝试定义一个皮肤类型,我假设您希望它是不可变的)。您不应该使用Decorator模式真正做到这一点(隐藏对象的不可变属性),因为如果对象在Decorator范围之外可用,它将提供不同的皮肤类型(如您所定义的)。装饰器通常不会更改正在装饰的对象的现有属性

也许更好的例子是HibernationDecorator。由于基类与休眠无关,所以您可能希望制作该装饰器,以便为您的兔子提供休眠功能。这就是Decorator所要做的——提供基类或接口契约中不存在的附加功能,同时仍然遵守基类的契约

我不知道我是否完全理解你的问题。我是这样读的:

你的装饰师还没有完成。如图所示,它仍然是抽象和不完整的:

abstract class AnimalDecorator extends Animal {
    protected $animal;

    public function __construct(Animal $animal) {
        $this->animal = $animal;
    }
}
如果你想让它更容易工作,你也应该装饰所有的方法,所以当你从
AnimalDecorator
扩展时,你不需要这样做。以下是众多方法中的两种:

abstract class AnimalDecorator extends Animal {

    ...

    public function getSkinColor() {
        return $this->animal->getSkinColor();
    }

    public function setSleep($hours) {
        $this->animal->setSleep($hours);
    }


    ...
在委派所有方法后,您可以像以前一样在混凝土装饰器中重写您想要的方法:

class ReptileSkinDecorator extends AnimalDecorator {
    public function getSkinColor() {
        return "reptile";
    }
}

听起来你试图强制使用一种不适合问题的特定模式。装饰师通常会聚集一些额外的东西(在头发上添加辫子),而不是完全改变它,就像你试图处理皮肤一样(头发到鳞片)

(通过指定对象的构建方式)可以更好地解决问题。在你的例子中,你想要用爬行动物的皮肤建造一只兔子。(我来自哪里,而不是爬行动物的皮肤,制作一只有角的兔子并称之为:)会很有趣

我认为在这里使用构造器(或任何模式)实际上可能有些过分。对于这个特殊的问题,你一定要使用一种模式吗?按照以下方式定义代码,暂时不考虑模式,怎么样

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";
    }
}

<强>免责声明: IM是C++的家伙,我的PHP很差,我确信这个代码有几个问题,但是我希望你能理解。


因此,兔子只会延伸动物,并相应地设置其属性。然后,如果有人想要一只兔子爬行动物,他们可以扩展兔子(可能是过度捕杀),或者只是制作一只兔子,并相应地设置皮肤类型。

今天再也不能投票了,这是我在回答中试图用代码描述的更好的措辞。我认为真正的问题是他试图强制使用一种不符合问题的特定模式。我认为OP的例子只是试图找到一种使用模式的方法。鉴于Green不理解该模式的目的,因此选择的示例并不真正适合该模式也就不足为奇了。只是我的解释,你能说说哪本书吗?简单。伟大的我想给+1,但我没有票数:/。但保持简单就是coo