一、概述
动态的给一个对象增加一些额外的职责,增加对象的功能来说,装饰者模式比生成子类实现更加灵活,装饰者模式石一种对象结构性模式。
二、装饰者对象角色
Component(抽象构件)
它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
ConcreteComponent(被装饰者)
它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
Decorator(抽象装饰类)
它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
ConcreteDecorator(具体装饰类)
它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
由于具体构件类和装饰类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。
三、代码实现
需求:
在双11 就要来临之际,电商为了促销,想出了各种手段,比如打折,发红包等等,这里就可以用到装饰者模式。购买商品的款项为 被装饰者对象。红包可以认为是装饰器,打折也是。
1、抽象构建
package decorator.demo;
import java.math.BigDecimal;
public interface Component {
BigDecimal getCount();
}
2、被装饰者
package decorator.demo;
import java.math.BigDecimal;
public class FactPrice implements Component{
@Override
public BigDecimal getCount() {
return new BigDecimal(100);
}
}
3、抽象装饰器
package decorator.demo;
import java.io.Serializable;
import java.math.BigDecimal;
public class Decorator implements Component {
// 被装饰的对象
private Component component;
@Override
public BigDecimal getCount() {
return this.component.getCount();
}
public void setComponent(Component decorator) {
this.component = decorator;
}
}
4、红包
package decorator.demo;
import java.math.BigDecimal;
public class RedDecorator extends Decorator{
@Override
public BigDecimal getCount() {
return super.getCount().subtract(new BigDecimal("5"));
}
}
5、折扣
package decorator.demo;
import java.math.BigDecimal;
public class DiscountDecortor extends Decorator{
@Override
public BigDecimal getCount() {
return super.getCount().multiply(new BigDecimal("0.8"));
}
}
6、调用者
package decorator.demo;
import java.util.ArrayList;
import java.util.List;
public class Invoker {
public static void main(String[] args){
Component user = new FactPrice();
System.out.println("原始的价格:"+user.getCount());
List<Decorator> decorators = new ArrayList<>();
decorators.add(new RedDecorator());
decorators.add(new DiscountDecortor());
for(Decorator decorator:decorators){
decorator.setComponent(user);
user = decorator;
System.out.println("优惠后的价格:"+user.getCount());
}
System.out.println("最终的价格:"+user.getCount());
}
}
这里我们先 得到100块,减掉5块钱红包,在在这个基础上打8折。结果是76块。
也可以调整优惠顺序,可以 先打八折,在减掉5块。结果需要75块。
执行结果:
在实际的应用中,这些装饰者,可以通过调整装饰者类顺序或者根据不同的场景使用不同的装饰者,实现灵活的打折策略。