一、装饰器模式概述
装饰器模式(装饰者模式)定义:装饰器模式动态地将责任附加到对象上。若要拓展功能,装饰者提供了比继承更有弹性地替代方案。(对象结构型模型)通俗点来说:动态的给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。
- 利用继承来达到“类型匹配”:
- 1.装饰者与被装饰对象有相同地超类型;
- 2.可以用一个或多个装饰者包装一个对象;
- 3.既然装饰者与被装饰对象有相同地超类型,所以在任何需要原始对象(被包装地)的场合,可以用装饰过的兑现代替它;
- 4.装饰者可以在所委托被装饰者的行为之前与/之后,加上自己的行为,以达到特定的目的;
- 5.对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
- 装饰模式分析:
- 1.可以在不改变一个对象本身功能的基础上给对象增加额外的新行为;
- 2.是一种用于替代继承的技术,它通过一种无需有定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系;
- 3.引入了装饰类,在装饰类中既可以调用装饰的原有类的方法,还可以增加新的方法,以扩展原有类的功能。
透明装饰模式与半透明装饰模式
- 半透明装饰模式:
- 1.可以给系统带来更多的灵活性,设计相对简单,使用起来也方便;
- 2.客户端使用具体装饰类型来定义装饰后的对象,因此可以单独调用addedBehavior()方法;
- 3.最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象;
- 4.用具体装饰定义装饰之后的对象,而具体构件使用抽象构件类型来定义;
- 5.对于客户而言,具体构件类型无须关心,是透明的;但是具体装饰类型必须指定,这并不是透明的。
- 透明装饰模式:
- 1.要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型;
- 2.对客户端而言,具体构件对象和具体装饰对象没有任何区别;
- 3.可以让客户透明地使用装饰之前地对象和装饰之后地对象,无须关心他们的区别;
- 4.可以对一个已装饰过地对象进行多次装饰,得到更多复杂、功能更为强大的对象;
- 5.无法在客户端单独调用新增addedBehavior()方法
- 适用环境:
- 1.在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;
- 2.当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式
装饰者模式优缺点
- 优点:
- 1.对于扩展一个对象功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加;
- 2.可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为;
- 3.可以对一个对象进行多次装饰;
- 4.具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,且原有类库代码无需变化,符合开闭原则。
- 缺点:
- 1.使用装饰模式进行系统设计时将产生很多小对象,大量对象对象的产生势必会占用更多的系统资源,在一定程度上影响程序的性能;
- 2.比继承更加易于出错,排错也更困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。
二、代码实现
结构包含四个角色:
- 抽象构件(Component)
- 具体构件(ConcreteComponent)
- 抽象装饰类(Decorator)
- 具体装饰类(ConcreteDecorator)
2.1 星巴兹咖啡
2.1.1 抽象构件(抽象基类饮料Beverage)
package decorator.dec;
//抽象构件:饮料
public abstract class Beverage {
String description = "Unknown Noodle";
int size;
//小杯TALL、中杯GRANDE、大杯WENTI
public final static int TALL=1;
public final static int GRANDE=2;
public final static int WENTI=3;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public abstract double cost();
}
2.1.2 具体构件(基于饮料的咖啡:DarkRoast、Decaf、Espressio、HouseBlend)
package decorator.dec;
//意大利浓咖啡
public class DarkRoast extends Beverage{
public DarkRoast() {
description = "DarkRoast";
}
public double cost() {
return 3;
}
}
package decorator.dec;
//不加咖啡因的咖啡
public class Decaf extends Beverage{
public Decaf() {
description = "Decaf";
}
public double cost() {
return 2;
}
}
package decorator.dec;
//意式浓缩咖啡
public class Espressio extends Beverage{
public Espressio() {
description = "Espressio";
}
public double cost() {
return 2.5;
}
}
package decorator.dec;
//混合咖啡
public class HouseBlend extends Beverage{
public HouseBlend() {
description = "HouseBlend";
}
public double cost() {
return 1.5;
}
}
2.1.3 抽象装饰类(抽象装饰类CondimentDecorator)
package decorator.dec;
//抽象装饰类:描述->>配料继承父类,附加在父类上
public abstract class CondimentDecorator extends Beverage{
Beverage beverage;
public abstract String getDescription();
}
2.1.4 具体装饰类(添加在咖啡上的牛奶milk、抹茶Mocha、豆奶Soy、咖啡的大小Size、搅拌Whip)
package decorator.dec;
//牛奶
public class milk extends CondimentDecorator{
public milk(Beverage beverage) {
this.beverage=beverage;
}
public String getDescription() {
return beverage.getDescription() + ",Milk";
}
public double cost() {
return 1+beverage.cost();
}
}
package decorator.dec;
//抹茶
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
this.beverage=beverage;
}
@Override
public String getDescription() {
// TODO 自动生成的方法存根
return beverage.getDescription() + ",Mocha";
}
public double cost() {
return 1+beverage.cost();
}
}
package decorator.dec;
//豆奶
public class Soy extends CondimentDecorator {
public Soy(Beverage beverage) {
this.beverage=beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ",Soy";
}
public double cost() {
return 1+beverage.cost();
}
}
package decorator.dec;
//大小
public class Size extends CondimentDecorator {
public Size(Beverage beverage,int size) {
this.beverage = beverage;
this.size=size;
}
@Override
public String getDescription() {
// TODO 自动生成的方法存根
if(size == beverage.TALL) {
return beverage.getDescription() + ",小杯";
}else if(size == beverage.GRANDE) {
return beverage.getDescription() + ",中杯";
}else if(size == beverage.WENTI) {
return beverage.getDescription() + ",大杯";
}
return null;
}
@Override
public double cost() {
double cost = beverage.cost();
if(size == beverage.TALL) {
cost += 0.1;
}else if(size == beverage.GRANDE) {
cost +=0.2;
}else if(size == beverage.WENTI) {
cost +=0.3;
}
return cost;
}
}
package decorator.dec;
//搅拌
public class Whip extends CondimentDecorator {
//Noodle beverage;
public Whip(Beverage beverage) {
this.beverage=beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ",Whip";
}
public double cost() {
return 1+beverage.cost();
}
}
2.1.5 main方法实现装饰者模式
package decorator.dec;
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Beverage beverage1 =new Mocha(new milk(new DarkRoast()));
System.out.println(beverage1.getDescription()+" 合计$"+beverage1.cost());
Beverage beverage2 =new Mocha(new milk(new DarkRoast()));
Beverage beverage3 =new Size(new Mocha(new milk(new DarkRoast())),2);
Beverage size = new Size(beverage2,2);
System.out.println(size.getDescription()+" 合计$"+size.cost());
}
}
2.1.6 UML图
2.2 窗口显示
2.2.1 抽象构件(抽象基类:显示构件Component)
package decorator.visualCompanent;
//显示构件
public abstract class Component {
public abstract void display();
}
2.2.2 具体构件(列表框、文本框、窗体)
package decorator.visualCompanent;
public class ListBox extends Component {
@Override
public void display() {
// TODO 自动生成的方法存根
System.out.println("显示列表框!");
}
}
package decorator.visualCompanent;
public class TextBox extends Component {
@Override
public void display() {
// TODO 自动生成的方法存根
System.out.println("显示文本框!");
}
}
package decorator.visualCompanent;
public class Window extends Component {
@Override
public void display() {
// TODO 自动生成的方法存根
System.out.println("显示窗体!");
}
}
2.2.3 抽象装饰类(ComponentDecorator)
package decorator.visualCompanent;
public class ComponentDecorator extends Component{
private Component component;//维持对抽象构件类型对象的引用
//注入抽象构件类型的对象
public ComponentDecorator(Component component) {
this.component = component;
}
public void display() {
component.display();
}
}
2.2.4 具体装饰类(增加新的构件:黑色边框和滚动条)
package decorator.visualCompanent;
public class BlackBorderDecorator extends ComponentDecorator {
public BlackBorderDecorator(Component component) {
super(component);
}
public void display() {
// TODO 自动生成的方法存根
this.setBlackBorder();
super.display();
}
public void setBlackBorder() {
System.out.println("为构件增加黑色边框!");
}
}
package decorator.visualCompanent;
public class ScrollBarDecorator extends ComponentDecorator {
public ScrollBarDecorator(Component component) {
super(component);
}
public void display() {
// TODO 自动生成的方法存根
this.setScrollBar();
super.display();
}
public void setScrollBar() {
System.out.println("为构件增加滚动条!");
}
}
2.2.5 main方法实现装饰者模式
package decorator.visualCompanent;
public class Client {
public static void main(String[] args) {
// TODO 自动生成的方法存根
//使用抽象构件定义全部对象
Component component,componentSB,componentBB;
component = new Window(); //创建具体对象
//创建装饰后的构件对象
componentSB = new ScrollBarDecorator(component);
//将装饰了一次的对象
componentBB = new BlackBorderDecorator(componentSB);
componentBB.display();
}
}