每当我们买了新房子之后,相信绝大部分人都会进行装修,给房子增加一些其他新的物品。不过,无论如何装修,这个房子还是这个房子,最本质的东西并没有变,有的只是我们通过装修的方式,给这个房子增加了一些额外的功能.....
通过装修的方式,给房子增加一些我们想要的额外功能,这种方式,就类似于我们今天要讲的设计模式:装饰者模式。
1.装饰模式概念
装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。例如上面的房子装修,我们买了手机之后给手机装上手机壳,贴上手机膜等。这些,都可以说是装修模式的应用。
不过这里需要注意的是,装修模式与继承不一样,继承是需要一个子类来拓展对象的功能,而装饰模式则不一样,它是通过定义一个装饰类,在这个装饰类中持有某些对象的引用,然后通过使用对象之间的关联关系来取代类之间的继承关系。
2.定义
装饰模式(Decorator Pattern):在不必改变原类文件和原类使用的继承的情况下,动态地扩展一个对象的功能。就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
角色
和观察者模式类似,观察者模式一般会有如下四个角色:
- 抽象构件(Component).
- 具体构件(ConcreteComponet)。
- 抽象装饰类(Decorator)。
- 具体装饰类(ConcreteDecorator)。
下面介绍下四个角色的一些功能、任务。
- 抽象构件:它是具体构件和抽象装饰类的共同父类,声明了要在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象。抽象构件一般定义为接口。
- 具体构件:它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰对象可以给它增加额外的职责(方法)。
- 抽象装饰类:它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
- 具体装饰类:它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
下面我给个例子吧,看个例子就比较知道这些角色都是个什么情况了。
3.例子
在n年前,人类捕捉了动物之后,会直接杀了之后就拿来吃,而不会把它烤熟、弄上一些配料之后再吃。但是到了后来,人类就懂得了把动物烤熟、弄上配料之后再吃了。
现在我们假设人类本来是不会烤熟之后再吃的,而是被装饰了一些额外的能力之后,才知道烤熟之后再吃。(貌似这个例子有点勉强.....)。
现在开始定义上面那四个角色:
1.抽象构件
/**
* 定义作为人类应有的一些规范
*/
public interface Human {
void eating();
}
2.具体构件
/**
* 具体构件类
*/
public class Man implements Human{
@Override
public void eating() {
System.out.println("吃刚刚捕获的美味佳肴");
}
}
3.抽象装饰类
/**
* 抽象装饰者,需要实现抽象构件接口
*/
public class Decorator implements Human{
//维持对抽象构件的引用
private Human human;
//注入构件实例
public Decorator(Human human) {
this.human = human;
}
@Override
public void eating() {
human.eating();
}
}
注意: 在Decorator中并未真正实现eat()方法,而只是调用原有Human对象的eating()方法,它没有真正实施装饰,而是提供一个统一的接口,将具体装饰过程交给子类完成。
4.具体装饰类
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Human human){
super(human);
}
@Override
public void eating() {
System.out.println("把捕捉的动物给烤熟了,在加些配料");
super.eating();
System.out.println("吃完饭之后洗手");
}
//需要增加的其他方法
}
5.测试类
public class Demo {
public static void main(String[] args){
Human man = new Man();
//没进行装饰之前
man.eating();
System.out.println("--------------------");
//进行装饰之后
man = new ConcreteDecorator(man);
man.eating();
}
}
6.打印结果
吃刚刚捕获的美味佳肴
--------------------
把捕捉的动物给烤熟了,在加些配料
吃刚刚捕获的美味佳肴
吃完饭之后洗手
从这个简单的例子可以看到,没有并没有改变原来的Man类,同时也没有定义他的子类来进行功能的拓展,而是通过一个装饰类的辅助来实现Man类功能的增强,这就是装饰者模式的作用。
优缺点
优点:
1,使用装饰者模式比使用继承更加灵活,因为它选择通过一种动态的方式来扩展一个对象的功能,在运行时可以选择不同的装饰器,从而实现不同的行为。
2,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
3,具体构件类与具体装饰类可以独立变化,他能是低耦合的。用户可以根据需要来增加新的具体构件类和具体装饰类,在使用时再对其进行各种组合,原有代码无须改变,符合“开闭原则”。
缺点:
1,会产生很多的小对象,增加了系统的复杂性
2,由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。
参考资料:
- 设计模式java版。
- Head First设计模式
完
关注公我的众号:苦逼的码农,获取更多原创文章,后台回复礼包送你一份时下热门的资源大礼包。同时也感谢把文章介绍给更多需要的人