装饰模式(Decorator)
装饰模式就是给一个对象增加一些新的功能,而且是动态的,此时就要要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。就像我们花了几百万买了房子,然后每个人都会根据自己的想法来给自己装修房子而不是开发商统一给我们一套已经装修的房子,还有就是去超市买东西,超市会根据我们买的东西,然后出具一个样式统一且详情不一样的账单。接着我们来举例超市买东西吧,大家会经常去超市,而考虑到房子不好买,大家也很少买过,装修过(哈哈)。
首先,根据上面的道理,我们来声明一个统一样式的账单接口:
/**
* @author chenglezheng
*/
public interface Menu {
float getPrice(); //商品单价
void setCount(int count); //设置购买数量
float getGoodsTotalCost(); //小计一下购买的商品金额
float getTotalCost(); //获取所有商品的总计
String getMenuInfo(); //账单明细
}
接着我们来找超市了,下面是我们找到的超市,这超市实现了上面的账单接口
/**
* @author chenglezheng
*/
public class SuperMarket implements Menu {
public float getPrice() {
return 0;
}
public void setCount(int count) {
}
public float getGoodsTotalCost() {
return 0;
}
public float getTotalCost() {
return 0;
}
public String getMenuInfo() {
return "乐创超市账单:\n"; //账单上先打印超市名
}
}
当然,超市里面有很多商品,这些商品琳琅满目的摆放着,上面都有名称,价格,我们所有的商品都要通过统一的账单接口扫码到总账单上,那么自然所有的商品都要实现上面的Menu接口:
/**
* @author chenglezheng
* 饼干
*/
public class Cake implements Menu{
private Menu menu;
private int count;
public Cake(Menu menu) {
this.menu = menu;
}
public String getMenuInfo() {
return menu.getMenuInfo()+"Cake:"+"单价:"+getPrice()+" 数量:"+this.count+" 小计:"+getGoodsTotalCost()+"\n";
}
public float getPrice() {
return 2.0f;
}
public void setCount(int count) {
this.count=count;
}
public float getGoodsTotalCost() {
return (this.count*getPrice());
}
public float getTotalCost() {
return this.menu.getTotalCost()+(this.count*getPrice());
}
}
/**
* @author chenglezheng
* @可乐
*/
public class Coca implements Menu{
private Menu menu;
private int count;
public void setCount(int count) {
this.count=count;
}
public Coca(Menu menu) {
this.menu=menu;
}
public float getPrice() {
return 6.5f;
}
public float getGoodsTotalCost() {
return (this.count*getPrice());
}
public String getMenuInfo() {
return menu.getMenuInfo()+"Coca:"+"单价:"+getPrice()+" 数量:"+this.count+" 小计:"+getGoodsTotalCost()+"\n";
}
public float getTotalCost() {
return this.menu.getTotalCost()+(this.count*getPrice());
}
}
最后我们选好东西准备结账了:
/**
* @author chenglezheng
*
*/
public class DecatorTest {
public static void main(String[] args) {
Menu menu=new SuperMarket(); //扫码系统默认打印好超市的基本信息
Menu cake=new Cake(menu); //把扫好的默认信息放到账单里,开始扫码饼干
cake.setCount(2); //买了2盒饼干
Menu coca=new Coca(cake);//把上面扫好的信息再放到账单里,开始扫码可乐
coca.setCount(1); //买了1瓶
System.out.println(coca.getMenuInfo()); //打印账单明细
System.out.println("总价: "+coca.getTotalCost()); //打印账单中商品总价
}
}
输出结果:
乐创超市账单:
Cake:单价:2.0 数量:2 小计:4.0
Coca:单价:6.5 数量:1 小计:6.5
总价: 10.5
小结:
装饰器模式的应用场景:
1、需要扩展一个类的功能。
2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
3、输入输出流中大量使用装饰者模式。
缺点:产生过多相似的对象,不易排错,且容易发生类爆炸。