案例:小菜出门约会穿衣
第一版代码:
class Person {
private $name;
public function __construct($name)
{
$this->name = $name;
}
public function WearTShirts()
{
echo '大T恤 ';
}
public function WearBigTrouser()
{
echo '跨裤 ';
}
public function WearSneakers()
{
echo '破球鞋 ';
}
public function WearSuit()
{
echo '西装 ';
}
public function WearTie()
{
echo '领带 ';
}
public function WearLeatherShoes()
{
echo '皮鞋 ';
}
public function Show()
{
echo "装扮的{$this->name}";
}
}
//客户端代码
$Person = new Person('小菜');
echo "第一种装扮:";
$Person->WearTShirts();
$Person->WearBigTrouser();
$Person->WearSneakers();
$Person->Show();
echo "\n第二种装扮:";
$Person->WearSuit();
$Person->WearTie();
$Person->WearLeatherShoes();
$Person->Show();
功能是实现了,如果要加入“超人”的装扮,就得修改Person类,这样就违反了开放-封闭原则了。
第二版代码:
把这些服饰都写成子类
class Person {
private $name;
public function __construct($name)
{
$this->name = $name;
}
public function Show()
{
echo "装扮的{$this->name}";
}
}
//服饰抽象类
abstract class Finery {
public abstract function Show();
}
//大T恤子类
class TShirts extends Finery {
public function Show()
{
// TODO: Implement Show() method.
echo '大T恤 ';
}
}
//跨裤子类
class BigTrouser extends Finery {
public function Show()
{
// TODO: Implement Show() method.
echo '跨裤 ';
}
}
//破球鞋子类
class Sneakers extends Finery {
public function Show()
{
// TODO: Implement Show() method.
echo '破球鞋 ';
}
}
//西装子类
class Suit extends Finery {
public function Show()
{
// TODO: Implement Show() method.
echo '西装 ';
}
}
//领带子类
class Tie extends Finery {
public function Show()
{
// TODO: Implement Show() method.
echo '领带 ';
}
}
//皮鞋子类
class LeatherShoes extends Finery {
public function Show()
{
// TODO: Implement Show() method.
echo '皮鞋 ';
}
}
//客户端代码
$Person = new Person('小菜');
echo "第一种装扮:";
$dtx = new TShirts();
$kk = new BigTrouser();
$pqx = new Sneakers();
$dtx->Show();
$kk->Show();
$pqx->Show();
$Person->Show();
echo "\n第二种装扮:";
$xz = new Suit();
$ld = new Tie();
$px = new LeatherShoes();
$xz->Show();
$ld->Show();
$px->Show();
$Person->Show();
第三版代码:
角色:
- 组件对象的接口: 定义给这些对象动态添加职责的方法
- 待装饰对象: 被扩展的对象。
- 所有装饰器的父类: 实现 组件对象的接口,并持有一个Component对象(该对象其实就是被装饰的对象),定义添加职责的方法,使其调用Component对象的添加职责方法。
- 具体的装饰器类: 实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象
//组件对象接口
interface IComponent {
public function Display();
}
//待装饰对象
class Person implements IComponent {
private $name;
public function __construct($name)
{
$this->name = $name;
}
public function Display()
{
// TODO: Implement Display() method.
echo "装饰的: {$this->name} \n";
}
}
//所有装饰器父类
class Clothes implements IComponent {
protected $component;
public function Decorate(IComponent $component)
{
$this->component = $component;
}
public function Display()
{
// TODO: Implement Display() method.
if(!empty($this->component))
{
$this->component->Display();
}
}
}
//------------------------------具体装饰器----------------
//大T恤子类
class TShirts extends Clothes {
public function Display()
{
echo "大T恤 ";
parent::Display(); // TODO: Change the autogenerated stub
}
}
//跨裤子类
class BigTrouser extends Clothes {
public function Display()
{
echo "跨裤 ";
parent::Display(); // TODO: Change the autogenerated stub
}
}
//破球鞋子类
class Sneakers extends Clothes {
public function Display()
{
echo "破球鞋 ";
parent::Display(); // TODO: Change the autogenerated stub
}
}
//西装子类
class Suit extends Clothes {
public function Display()
{
echo "西装 ";
parent::Display(); // TODO: Change the autogenerated stub
}
}
//领带子类
class Tie extends Clothes {
public function Display()
{
echo "领带 ";
parent::Display(); // TODO: Change the autogenerated stub
}
}
//皮鞋子类
class LeatherShoes extends Clothes {
public function Display()
{
echo "皮鞋 ";
parent::Display(); // TODO: Change the autogenerated stub
}
}
//客户端代码
$Person = new Person('小菜');
echo "第一种装扮:";
$dtx = new TShirts();
$kk = new BigTrouser();
$pqx = new Sneakers();
$pqx->Decorate($Person);
$kk->Decorate($pqx);
$dtx->Decorate($kk);
$dtx->Display();
echo "第二种装扮:";
$xz = new Suit();
$ld = new Tie();
$px = new LeatherShoes();
$px->Decorate($Person);
$ld->Decorate($px);
$xz->Decorate($ld);
$xz->Display();
对客户端调用解释:
$Person = new Person('小菜');
创建一个待装饰对象 ,也是一个Component对象
$dtx = new TShirts();
$kk = new BigTrouser();
$pqx = new Sneakers();
创建了3个具体的装饰器类,也就是3个Component对象
$pqx->Decorate($Person);
把待装饰对象放进具体装饰器Sneakers中,$pqx
的component为$Person
对象
$kk->Decorate($pqx);
把$pqx
对象放进具体装饰器BigTrouser中,$kk
的component为$pqx
对象
$dtx->Decorate($kk);
把$kk
对象放进具体装饰器TShirts中,$dtx
的component为$kk
对象
$dtx->Display();
$dtx
调用自身的Display()方法,输出“大T恤”,之后调用父类的Display()方法,父类的Display()方法操作是component对象调用Display(),也就是$dtx
的component对象$kk
调用Display()方法;
$kk
调用自身的Display()方法,输出“跨裤”,之后调用父类的Display()方法,父类的Display()方法操作是component对象调用Display(),也就是$kk
的component对象$pqx
调用Display()方法;
$pqx
调用自身的Display()方法,输出“破球鞋”,之后调用父类的Display()方法,父类的Display()方法操作是component对象调用Display(),也就是$pqx
的component对象$Person
调用Display()方法;
$Person
调用自身的Display()方法,输出“装饰的: 某某某”结束。
适用场景:
1. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
2. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
3. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。