装饰器模式在java中很常见,其中心的本质思想就是动态组合,这种组合很精妙的实现了生活中类似于定制化的功能,可以按照客户的要求来满足客户的定制场景,同时又让编码变得没有那么的复杂,学好了装饰模式,能真正的理解面向对象编程的 本质,也会让人有一种豁然开朗的感觉。
java中常用的装饰模式的地方就是我们熟知的IO流,InputStream系列和OutputStream系列都是状态模式的设计体现。有了这种模式,我们就可以很方便的将一个对象选择写入到一个file中还是写成内存byte中,使用方可以根据自己的需求定制,而且不用再根据业务场景增加多余的类;
每个类的功能如下:
实现思路
装饰器模式在具体的实现中,首先要有一个组件对象,这是实现装饰器对象的基础,这个可以是一个接口,也可以是一个抽象类,其次,我们需要实现一个或者多个组件的实现类,座位被装饰的原始对象,原始对象的意思就是没有装饰之前的对象,比如IO中的file和byte两个流,这两个流就是同一个级别的原始对象。然后才是我们的重点,装饰器的设计:首先我们要实现一个抽象的Decorator对象,这个对象首先需要实现或者继承原来的装饰组件(Component),因为我们就是为了装饰那个组件的实现类,当然要有相同的方法;其次就是需要持有一个组件对象,这是因为我们完成了装饰逻辑以后,还是需要被装饰的对象去执行功能。抽象的装饰对象(Decorator)还是很有必要的,虽然我们可以直接实现装饰器的实现类,但是那样就需要在每个实现类中注入每个组件对象,没法统一规范,写这样一个对象,就可以统一规范注入什么样的组件对象,也规范了和组件对象相同的方法。
在具体的使用中,我们先创建被装饰的原始对象(ConcreteComponent),然后创建具体的装饰对象(ConcreteDecorator),将组件对象注入到装饰对象中,然后调用装饰对象的方法,就可以完成装饰工作。
我们用促销的例子来举例,来实现一个具体的促销场景。为了演示装饰模式的扩展性,首先我们先假设该促销目前有两个活动,一个是团购活动,一个是节假日促销活动。实现思路和代码如下:
/**
* 促销活动的抽象类
*/
public abstract class AbstractSalePromotion {
/**
* 获得活动价格
*
* @return :
*/
abstract double getPromotionPrice();
}
/**
* 原始产品
*/
public class OriginalProduct extends AbstractSalePromotion {
@Override
double getPromotionPrice() {
// 原始产品,没有折扣
return 100;
}
}
/**
* 装饰器的抽象类
*/
public abstract class AbstractDecorator extends AbstractSalePromotion {
private AbstractSalePromotion salePromotion;
public AbstractDecorator(AbstractSalePromotion salePromotion) {
this.salePromotion = salePromotion;
}
@Override
double getPromotionPrice() {
return salePromotion.getPromotionPrice();
}
}
/**
* 团购活动价
*/
public class GroupSalePromotion extends AbstractDecorator{
public GroupSalePromotion(AbstractSalePromotion salePromotion) {
super(salePromotion);
}
@Override
double getPromotionPrice() {
double promotionPrice = super.getPromotionPrice();
System.out.println("团队折扣:打九折!!!");
return promotionPrice * 0.9;
}
}
/**
* 节假日折扣
*/
public class HolidaySalePromotion extends AbstractDecorator{
public HolidaySalePromotion(AbstractSalePromotion salePromotion) {
super(salePromotion);
}
@Override
double getPromotionPrice() {
double promotionPrice = super.getPromotionPrice();
System.out.println("节假日折扣:打八折!!!");
return promotionPrice * 0.8;
}
}
public class Client {
/**
* 只有团队折扣
*/
@Test
public void testGroupSalePromotion() {
AbstractSalePromotion salePromotion = new GroupSalePromotion(new OriginalProduct());
System.out.println("最终价格:" + salePromotion.getPromotionPrice());
}
}
执行结果:
-------------------------------------------------------------
团队折扣:打九折!!!
最终价格:90.0
/**
* 两个团队折扣
*/
@Test
public void testDoubleGroupSalePromotion() {
System.out.println("-------------------------------------------------------------");
AbstractSalePromotion salePromotion = new GroupSalePromotion(new GroupSalePromotion(new OriginalProduct()));
System.out.println("最终价格:" + salePromotion.getPromotionPrice());
}
-------------------------------------------------------------
团队折扣:打九折!!!
节假日折扣:打八折!!!
最终价格:72.0
要是有个极端的场景,一个客户拿到了两个团购的折扣,我们也可以轻松的实现,创建两个团购装饰类就行,而不是需要新建一个两个团购的装饰类,这就达到了根据客户动态定制的逻辑,测试代码和结果如下:
/**
* 两个团队折扣
*/
@Test
public void testDoubleGroupSalePromotion() {
System.out.println("-------------------------------------------------------------");
AbstractSalePromotion salePromotion = new GroupSalePromotion(new GroupSalePromotion(new OriginalProduct()));
System.out.println("最终价格:" + salePromotion.getPromotionPrice());
}
-------------------------------------------------------------
团队折扣:打九折!!!
团队折扣:打九折!!!
最终价格:81.0
/**
* 十周年庆折扣
*/
public class TenYearSalePromotion extends AbstractDecorator{
public TenYearSalePromotion(AbstractSalePromotion salePromotion) {
super(salePromotion);
}
@Override
double getPromotionPrice() {
double promotionPrice = super.getPromotionPrice();
System.out.println("十周年折扣:打五折!!!");
return promotionPrice * 0.5;
}
}
如果一个客户既是团购,又是在节假日,还在店庆那天来,而商场又满足优惠可以同时享受,我们也不用怕,只需要三个具体的装饰类相互包装,就能实现具体的逻辑,测试代码和结果如下:
/**
* 团队、节假日、十周年折扣
*/
@Test
public void testTenYearGroupAndHolidaySalePromotion() {
System.out.println("-------------------------------------------------------------");
AbstractSalePromotion salePromotion = new TenYearSalePromotion(
new HolidaySalePromotion(new GroupSalePromotion(new OriginalProduct())));
System.out.println("最终价格:" + salePromotion.getPromotionPrice());
}
-------------------------------------------------------------
团队折扣:打九折!!!
节假日折扣:打八折!!!
十周年折扣:打五折!!!
最终价格:36.0
后记
个人总结,欢迎转载、评论、批评指正