一、模式定义(What):
1.装饰模式(Decorator):
又称(Wrapper)动态的给一个对象添加一些额外的职责,就增加功能而言装饰模式相比生成子类(继承机制)更为灵活。
2.组成结构:
(1).Component(译:元组)抽象的装饰对象:该类可以是一个抽象类或者接口,是该模式最基本,最核心,最原始的对象。
(2).ConcreteComponent(译:真实元组)具体的装饰对象:是Component的具体实现类,我们要装饰的对象就是这个。
(3).Decorator(译:装饰器)装饰器:一般是一个抽象类,在它的属性中必然会有一个private变量指向Component抽象的装饰对象。
(4).ConcreteComponent(译:真实装饰器):具体的装饰器。
3.模式解读:
(1).具体的装饰器与具体的装饰对象实现了同一个接口(Component)/ 继承同一个抽象类。
(2).装饰器中使用了被装饰的对象。
二、必要性(Why):
当我们需要给某个类增加功能时,一般可通过两种方式实现:
(1).继承机制:通过继承实现新的子类,除了可以复用父类的方法外,还可以有效地在父类基础上增加新的功能。但是,用户不能控制增加功能的方式与时机。
(2).关联机制:即:将一个对象嵌入到另一个对象中,由另一个对象决定是否调用嵌入对象的功能以便扩展自己的功能。我们称这个嵌入的对象为装饰器。
装饰模式是以对客户端透明的方式动态的给一个对象增加新的职责。即:客户端并不会觉得对象在装饰前和装饰后有什么差别。总之:装饰模式可以在不增加子类的情况下,实现对象功能的扩展。
三、实现(How):
1、抽象的装饰对象类:
package com.design.decorator;
/**
* @ClassName: Component
* @Description:装饰对象的抽象类
* @author: wanjinYoung
* @date: 2018年8月20日 上午9:37:36
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public abstract class Component {
/**
* @Title: Operation
* @Description:抽象方法
* @param:
* @return: void
* @throws
*/
public abstract void Operation();
}
2、具体的装饰对象类:
package com.design.decorator;
/**
* @ClassName: ConcreteComponent
* @Description:装饰对象的具体类
* @author: wanjinYoung
* @date: 2018年8月20日 上午9:40:56
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class ConcreteComponent extends Component{
@Override
public void Operation() {
// TODO Auto-generated method stub
System.out.println("ConcreteComponent operation !");
}
}
3、抽象的装饰器类:
package com.design.decorator;
/**
* @ClassName: Decorator
* @Description:装饰器的抽象类
* @author: wanjinYoung
* @date: 2018年8月20日 上午9:42:29
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public abstract class Decorator extends Component{
//引入需要装饰的对象
private Component component = null;
/**
* @Title: Decorator
* @Description:无参数的构造方法
* @param:
* @throws
*/
public Decorator() {
super();
// TODO Auto-generated constructor stub
}
/**
* @Title: Decorator
* @Description:带有一个参数的构造方法
* @param: @param component
* @throws
*/
public Decorator(Component component) {
this.component = component;
}
@Override
public void Operation() {
// TODO Auto-generated method stub
this.component.Operation();
}
}
4、具体的装饰器类A:
package com.design.decorator;
/**
* @ClassName: ConcreteDecoratorA
* @Description:具体装饰类A
* @author: wanjinYoung
* @date: 2018年8月20日 上午9:50:02
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class ConcreteDecoratorA extends Decorator{
public ConcreteDecoratorA(Component component) {
super(component);
// TODO Auto-generated constructor stub
}
@Override
public void Operation() {
// TODO Auto-generated method stub
this.decorate();
super.Operation();
}
private void decorate() {
System.out.println("ConcreteDecoratorA decorate!");
}
}
5、具体的装饰器类B:
package com.design.decorator;
/**
* @ClassName: ConcreteDecoratorB
* @Description:具体的装饰类B
* @author: wanjinYoung
* @date: 2018年8月26日 下午4:50:39
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class ConcreteDecoratorB extends Decorator{
//无参构造
public ConcreteDecoratorB() {
super();
// TODO Auto-generated constructor stub
}
//有参构造
public ConcreteDecoratorB(Component component) {
super(component);
// TODO Auto-generated constructor stub
}
//重写父类的方法
@Override
public void Operation() {
// TODO Auto-generated method stub
this.decorate();
super.Operation();
}
//具体装饰类的独有方法
private void decorate() {
System.out.println("ConcreteDecoratorB decorate!");
}
}
6、测试类:
package com.design.decorator;
/**
* @ClassName: Client
* @Description:用于测试正确性
* @author: wanjinYoung
* @date: 2018年8月26日 下午4:55:56
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
component = new ConcreteDecoratorA(component);
component = new ConcreteDecoratorB(component);
component.Operation();
}
}
7、测试结果:
下面我们把猴子Monkey 的衣着装饰的方式过程,通过代码的方式进行实现。同时把每加穿一件衣服后的花费进行统计。
1、抽象的装饰对象类:
package com.designpattern.decorator.use;
/**
* @ClassName: Programer
* @Description:装饰对象的抽象类
* @author: wanjinYoung
* @date: 2018年8月26日 下午7:58:33
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public abstract class Programer {
//两个抽象方法
public abstract void dress();
public abstract double price();
}
2、具体的装饰对象类:
package com.designpattern.decorator.use;
/**
* @ClassName: ProgramerMonkey
* @Description:装饰对象的具体类 (要装饰的对象)
* @author: wanjinYoung
* @date: 2018年8月26日 下午8:03:58
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class ProgramerMonkey extends Programer {
@Override
public void dress() {
// TODO Auto-generated method stub
System.out.println("nothing!"+"当前花费 "+price()+"¥");
}
@Override
public double price() {
// TODO Auto-generated method stub
double price = 0;
return price;
}
}
3、抽象的装饰器类:
package com.designpattern.decorator.use;
/**
* @ClassName: Clothing
* @Description:抽象的装饰器类(服饰类)
* @author: wanjinYoung
* @date: 2018年8月26日 下午8:08:40
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public abstract class Clothing extends Programer{
private Programer programer;
//构造方法
public Clothing(Programer programer) {
super();
this.programer = programer;
}
@Override
public void dress() {
// TODO Auto-generated method stub
this.programer.dress();
}
@Override
public double price() {
// TODO Auto-generated method stub
return this.programer.price();
}
}
4、具体的装饰器类--背心:
package com.designpattern.decorator.use;
/**
* @ClassName: Vest
* @Description: 背心装饰类
* @author: wanjinYoung
* @date: 2018年8月26日 下午8:19:45
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class Vest extends Clothing{
//构造方法
public Vest(Programer programer) {
super(programer);
// TODO Auto-generated constructor stub
}
@Override
public void dress() {
// TODO Auto-generated method stub
super.dress();
System.out.println("穿上背心!"+"当前花费 "+price()+"¥");
}
@Override
public double price() {
// TODO Auto-generated method stub
//背心的价格
double price =20;
price = super.price()+price;
return price;
}
}
5、具体的装饰器类--衬衫:
package com.designpattern.decorator.use;
/**
* @ClassName: Shirt
* @Description:衬衫装饰器类
* @author: wanjinYoung
* @date: 2018年8月26日 下午8:25:15
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class Shirt extends Clothing{
//一定要保持被装饰的对象
public Shirt(Programer programer) {
super(programer);
// TODO Auto-generated constructor stub
}
@Override
public void dress() {
// TODO Auto-generated method stub
super.dress();
System.out.println("穿上衬衫!"+"当前花费 "+price()+"¥");
}
@Override
public double price() {
// TODO Auto-generated method stub
//衬衫的价格
double price =300;
price = super.price()+price;
return price;
}
}
6、具体的装饰器类--西装:
package com.designpattern.decorator.use;
/**
* @ClassName: Suit
* @Description:西装装饰器
* @author: wanjinYoung
* @date: 2018年8月26日 下午8:27:04
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class Suit extends Clothing{
//保持被装饰的对象
public Suit(Programer programer) {
super(programer);
// TODO Auto-generated constructor stub
}
@Override
public void dress() {
// TODO Auto-generated method stub
super.dress();
System.out.println("穿上西装!"+"当前花费 "+price()+"¥");
}
@Override
public double price() {
// TODO Auto-generated method stub
//西装价格
double price =3000;
price = super.price()+price;
return price;
}
}
7、测试类:
package com.designpattern.decorator.use;
/**
* @ClassName: Client
* @Description:测试类
* @author: wanjinYoung
* @date: 2018年8月26日 下午8:39:52
*
* @Copyright: 2018 www.wanjinYoung.com Inc. All rights reserved.
*/
public class Client {
public static void main(String[] args) {
Programer monkey = new ProgramerMonkey();
//用背心进行装饰
Clothing vest = new Vest(monkey);
//用衬衫进行装饰
vest = new Shirt(vest);
//用西装进行装饰
vest = new Suit(vest);
vest.dress();
System.out.println("一身行头,总共花费:" + vest.price()+"RMB");
}
}
8、测试结果:
五、应用场景:
1、在不影响其他对象的情况下,以动态的,透明的方式给某个对象增加功能。
2、需要动态的给对象增加功能,以及动态的撤销。
3、当不能使用继承实现对类的功能进行扩展或者采用继承不利于实现对类的功能进行扩展,比如当扩展类功能造成其子类数量膨胀,不便于后续维护;被final修饰的类无法被继承。
六、总结:
优点:
1、装饰模式是继承关系的一种更加灵活的替代方式。无论装饰器Decorator,无论装饰多少层,返回的对象还是Componet(继承关系或者接口实现关系所决定的),实现的还是is-a关系。
2、可以在不破坏原有继承体系的基础上实现对体系中的对象的功能进行增强。比如,对现有的继承体系中的基类进行功能增强,一种方式是可直接修改并增加基类的功能;另外一种方法就是,我们可以不破坏现有继承体系的情况下,单独对基类功能进行增强。
3、可以动态的扩展一个类的功能。
4、可以实现功能的任意组合。
5、装饰模式中的装饰类与装饰器类之间的低耦合,可以独立发展。用户可以根据实际的需要,实现新的具体装饰对象与具体装饰器对象,然后再根据实际的场景进行组合。
缺点:
1、装饰模式必然会引入多层装饰,多层装饰必然会带来系统的复杂度,增加学习和掌握的难度。
2、装饰模式较继承更加灵活,这种灵活性也更容易出错,对于多层装饰的类对象的调试会更加复杂(想想“剥洋葱”的场景)。
注:个人学习随记!
代码:https://github.com/youngwanjin/DesignPattern/tree/master/JavaTrying/bin/com/designpattern