借鉴一下大鸟/小菜两个人说的例子,我们来实现一下avatar系统,即换肤系统。
人物出场人手一条内裤,穿什么衣服用户自己搭配。考虑到衣服种类很多,上衣裤子鞋子搭配更多,可能随着系统的迭代,衣服种类会不断增加,基于开放封闭原则,对于易变化的点进行封装,使用扩展的方式来实现穿衣的操作,代码如下(java)
//finery class
public class Finery {
public void Show()
{
System.out.print("Underwear");
}
}
//t-shirt finery
public class TShirt extends Finery {
@Override
public void Show()
{
super.Show();
System.out.print(" Tshirt ");
}
}
//person class
public class Person {
void ShowFinery(Finery finery)
{
finery.Show();
}
}
//client
public class client{
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Person person = new Person();
Finery finery;
finery = new TShirt();//if you want dress UnderWear and T-shirt
//finery = new Finery();//if you just want to dress Underwear
person.ShowFinery(finery);
}
}
这样对于目前的需求来说,已经实现了开放-封闭原则,当你想换一件衣服,不穿T恤了,比如你想穿毛衣了,你可以增加一个 Sweater类,继承自Finery类,在实现展示函数的时候先调用父类(Finery)函数,然后再实现Sweater本身内容。
但是这样不是没有问题,按照以上的方式,研发人员可能违背里氏替换原则,也就是说在实现派生类的时候忘记/不想调用父类(Finery)相关函数,导致基础功能(穿内裤)没有实现,后果是你在ShowFinery展示你的服饰的时候,你没有穿内裤,注意哦,T恤和毛衣现在还都是上衣,我们没有穿裤子呢。
为了避免只穿上衣的问题,我们现在也实现裤子和鞋子,那么上面的实现实现方式又出现了一个问题,那就是面对多件上衣(m)、多条裤子(n)、多条鞋子(q) 的搭配,你需要实现m*n*q个类去实现所有的服饰展示,类的数量暴增,并且你有没有感觉到这么设计类十分的死板?如果初始的时候人物只实现基础功能(穿一条内裤遮羞),后面附件功能(穿什么上衣、什么裤子、什么鞋子)我们可以动态的增减改多好?装饰者实现的就是此类需求。
装饰者模式:动态的为一个对象附加新的职责。
特征:
一、动态的,即在程序运行过程中可以为对象附加职责。附加职责的方式有两种:一种是静态继承型,也就是我们经常使用的继承多态,这种方式是在编译的时候指定某个类对于基类增加了什么操作。一种是动态组合型,装饰者模式就是其中一个,这种方式是在软件运行的时候指定某个对象增加操作。
二、附加,即一个类已经实现了基础功能或部分功能,在此基础上动态的为这个类的对象增加新的职责。
实现:
Component:定义一个对象接口,可以给这些对象动态地添加职责;
ConcreteComponent:定义一个具体的Component,继承自Component,重写了Component类的虚函数;
Decorator:维持一个指向Component对象的指针,该指针指向需要被装饰的对象;并定义一个与Component接口一致的接口;
ConcreteDecorator:向组件添加职责。
我们来看一下上面的例子如何使用装饰者模式实现
//just abstract or interface to indicate the func of the component
public abstract class IFinery {
public abstract void Show();
}
//the basic func
public class Underwear extends IFinery {
public void Show()
{
System.out.print("Underwear");
}
}
// a abstract to decorator the component
public abstract class IFinaryDecorator extends IFinery {
private IFinery m_finery;
public void setFinary(IFinery finery)
{
m_finery = finery;
}
@Override
public void Show()
{
m_finery.Show();
}
}
//t-shirt decorator
public class TShirtDecorator extends IFinaryDecorator{
@Override
public void Show()
{
super.Show();
System.out.print("T-Shirt");
}
}
//bigtrouser decorator
public class BigTrouserDecorator extends IFinaryDecorator{
public void Show()
{
super.Show();
System.out.print(" BigTrouser");
}
}
//client
public class client{
/**
* @param args
*/
public static void main(final String[] args) {
// TODO Auto-generated method stub
Person person = new Person();
IFinery finery = new Underwear();
person.ShowFinery(finery);//if you just want to dress underwear
IFinaryDecorator TShirtDecorator = new TShirtDecorator();
TShirtDecorator.setFinary(finery);
TShirtDecorator.Show();//if you want dress underwear and T-Shirt
IFinaryDecorator bigtrouserDecorator = new BigTrouserDecorator();
bigtrouserDecorator.setFinary(TShirtDecorator);
bigtrouserDecorator.Show();//if you want dress underwear and T-Shirt and Bigtrouser
}
}
这样可以把服饰类的数量缩减到m+n+q的范围;
适用场景:
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。