装饰模式(Decorator Mode):是结构模式的一种,它又与代理模式差不多,只不过装饰模式装饰类里关联的是自己的父类。并且可以多层嵌套。把所需的功能按正确的顺序串联起来进行控制。装饰模式利用关联自己的父类来对对象进行封装。这样每个子类装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。
目录
1. 意图:
想要动态的扩展一个类。动态添加,动态撤销。
定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
2. 如何使用:
何时使用:1.扩展一个类的功能。
2.动态增加功能,动态撤销。
如何解决:在不增加很多子类的情况下扩展类,将具体功能职责划分,同时继承装饰器类。
优点:装饰类和被装饰类可以独立发展,不会相互耦合。装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
3. UML模板:
4. 关键代码:
public class DecoratorMode : MonoBehaviour
{
void Start()
{
ConcreteComponent concrete = new ConcreteComponent();
ConcreteDecoratorA concreteA = new ConcreteDecoratorA();
ConcreteDecoratorB concreteB = new ConcreteDecoratorB();
//装饰的方法是:首先用ConcreteComponent实例化对象C,然后用ConcreteDecoratorA
//的实例化对象d1来包装c,再用ConcreteDecoratorB的对象d2包装d1,最终执行d2的Operation()
concreteA.SetComponent(concrete);
concreteB.SetComponent(concreteA);
concreteB.Operation();
}
}
//定义一个对象接口,可以给这些对象动态的添加职责
public abstract class Component
{
public abstract void Operation();
}
public class ConcreteComponent : Component
{
public override void Operation()
{
Debug.Log("具体对象的操作");
}
}
public abstract class Decorator : Component
{
protected Component component;
public void SetComponent(Component component)//设置Componet
{
this.component = component;
}
public override void Operation()
{
if (component!=null)
{
component.Operation();
}
}
}
public class ConcreteDecoratorA : Decorator
{
private string addedState;//本类的独有功能,以区别于ConcreteDecoratorB
public override void Operation()
{
//首先运行原Ccomponent的Operation(),在执行本类的功能,如addedState,相当于对原Component进行了装饰
base.Operation();
addedState = "New State";
Debug.Log("具体装饰对象A的操作"+ addedState);
}
}
public class ConcreteDecoratorB : Decorator
{
public override void Operation()
{
//首先运行原Component的Operation(),在执行本类的功能,如AddedBehavior(),相当于对原Component进行了装饰。
base.Operation();
AddedBehavior();
Debug.Log("具体装饰对象B的操作");
}
//本类独有的方法,以区别于ConreteDecoratorB
private void AddedBehavior()
{
Debug.Log("AddedBehavior");
}
}
5. 实例:
UML图
代码
public class DecoratorModeDemo:MonoBehaviour
{
private void Start()
{
Person xc = new Person("小菜");
Debug.Log("\n第一种装扮:");
TShirts ts = new TShirts();
BigTrouser kuanku = new BigTrouser();
Necktie lingdai = new Necktie();
Leathershoes pixie = new Leathershoes();
Gymshoes qiuxie = new Gymshoes();
Jacket xizhuang = new Jacket();
kuanku.Decorate(xc);
lingdai.Decorate(kuanku);
pixie.Decorate(lingdai);
pixie.Show();
//Debug.Log("\n第二种装扮");
//pixie.Decorate(xc);
//qiuxie.Decorate(pixie);
//xizhuang.Decorate(qiuxie);
//xizhuang.Show();
}
}
public class Person
{
public Person() { }
private string name;
public Person(string name)
{
this.name = name;
}
public virtual void Show()
{
Debug.LogFormat("装扮的{0}",name);
}
}
public class Finery : Person
{
protected Person component;
//打扮
public void Decorate(Person component)
{
this.component = component;
}
public override void Show()
{
if (component != null)
{
component.Show();
}
}
}
public class TShirts : Finery
{
public override void Show()
{
base.Show();
Debug.Log("大T恤");
}
}
public class BigTrouser : Finery
{
public override void Show()
{
base.Show();
Debug.Log("垮裤");
}
}
public class Necktie : Finery
{
public override void Show()
{
base.Show();
Debug.Log("领带");
}
}
public class Leathershoes : Finery
{
public override void Show()
{
base.Show();
Debug.Log("皮鞋");
}
}
public class Gymshoes : Finery
{
public override void Show()
{
base.Show();
Debug.Log("球鞋");
}
}
public class Jacket:Finery
{
public override void Show()
{
base.Show();
Debug.Log("西装");
}
}
最后这个例子很有意思,base.Show()在控制台输出Debug.Log(“”)的下面。这样输出的时候是从后往前的。比如说你先西装,皮鞋,最后T恤。最后输出的是T恤皮鞋西装。反之,如我这样写则是正向输出。这里写要注意,一不注意很容易死循环的23333.
这里我们跟一下代码:
kuanku.Decorate(xc);
lingdai.Decorate(kuanku);
pixie.Decorate(lingdai);
pixie.Show();
最后我们执行的是皮鞋的show方法。我们把父方法带过来
public override void Show()
{
if (lingdai != null)
{
lingdai.Show();
}
// base.Show();
Debug.Log("皮鞋");
}
我们在把领带里面的show方法带进来
public override void Show()
{
if (lingdai != null)
{
//base.Show();
if(kuaku!=null)
{
kuaku.show();
}
Debug.log("领带");
////lingdai.Show();
}
// base.Show();
Debug.Log("皮鞋");
}
如上我们把pixie.Show()方法完整的展现出来
public override void Show()
{
if (lingdai != null)
{
if(kuaku!=null)
{
if(xc!=null)
{
xc.Show();
}
debug.log("垮裤");
}
Debug.log("领带");
}
Debug.Log("皮鞋");
}
执行顺序是xc,垮裤,领带,皮鞋。那如果代码是这样呢
public override void Show()
{
Debug.Log("西装");
base.Show();
}
如上我们把pixie.Show()方法完整的展现出来
public override void Show()
{
Debug.Log("皮鞋");
if (lingdai != null)
{
Debug.log("领带");
if(kuaku!=null)
{
debug.log("垮裤");
if(xc!=null)
{
xc.Show();
}
}
}
}
执行顺序是皮鞋,领带,垮裤,xc。
是不是很有趣呢。我们挖到了装饰模式的精髓。但是还是那句话,小心死循环。