早上,我去鸡蛋饼小摊拿买了一块鸡蛋饼,加了两煎蛋,加了火腿肠,加了生菜,还加了根油条。
吃的好饱。。。
人与动物区别在于,人不仅会吃,而且会思考。所以,这种场景,作为程序员,你应该怎么设计?
好说!
/** * 反面教材1(BOOM!类爆炸) */ class 鸡蛋饼{ public double cost() { return 3; } } class 鸡蛋饼With鸡蛋 extends 鸡蛋饼{ public double cost() { return super.cost() + 0.5; } } class 鸡蛋饼With火腿 extends 鸡蛋饼{ public double cost() { return super.cost() + 1; } }
/** * 反面教材2(违反开闭原则:类应该对扩展开放,对修改关闭) * 以后鸡蛋价格变了,或者加两个鸡蛋,或者再加一种别的调料,想一下你怎么设计? */ class 鸡蛋饼2{ /** *有鸡蛋 */ private boolean hasEgg; /** *有火腿 */ private boolean hasHuotui; public double cost() { double basecost =3; if(hasEgg) { basecost +=0.5; } if(hasHuotui) { basecost +=1; } return basecost; } /** * @return the hasEgg */ public boolean isHasEgg() { return hasEgg; } /** * @param hasEgg the hasEgg to set */ public void setHasEgg(boolean hasEgg) { this.hasEgg = hasEgg; } /** * @return the hasHuotui */ public boolean isHasHuotui() { return hasHuotui; } /** * @param hasHuotui the hasHuotui to set */ public void setHasHuotui(boolean hasHuotui) { this.hasHuotui = hasHuotui; } }
装饰者概念
动态地将责任附加到对象上,若要扩展功能,装饰者提供比继承更有弹性的替代方案。
设计理念
当我们设计的类不能满足我们的需求的时候,我们可能设计一个类去继承它,但是这样就会使对象之间高度的耦合。
这时,我们就可以换一种思路,将不能满足我们需求的类A嵌入到要扩展的功能的类B当中。
这里注意,我们将要扩展的功能设计为一个类B,当这个类构造时可以引入A,B将持有A对象实例。
这种方法,我们称之为:装饰者模式
使用场景
装饰模式的应用在java的I/O流中最为显著。
设计原则
对扩展开放,对修改关闭。
UML类图
示例
抽象组件
package com.study.headfirst.decorator; /** * 抽象组件 * @author mdl * @date 2019/12/05 */ public abstract class Pancake { public String desc = "我不是一个具体的饼"; /** * @return the desc */ public String getDesc() { return desc; } public abstract double cost(); }
鸡蛋饼(具体组件A)
package com.study.headfirst.decorator; /** * @author mdl * @date 2019/12/05 */ public class TornCake extends Pancake{ public TornCake() { desc ="鸡蛋饼"; } /* (non-Javadoc) * @see com.study.headfirst.decorator.Pancake#cost() */ @Override public double cost() { // TODO Auto-generated method stub return 4; } }
肉夹馍(具体组件B)
package com.study.headfirst.decorator; /** * @author mdl * @date 2019/12/05 */ public class Roujiamo extends Pancake{ public Roujiamo() { desc ="肉夹馍"; } /* (non-Javadoc) * @see com.study.headfirst.decorator.Pancake#cost() */ @Override public double cost() { // TODO Auto-generated method stub return 5; } }
抽象装饰者
package com.study.headfirst.decorator; /** * 抽象装饰者 * @author mdl * @date 2019/12/05 */ public abstract class Condiment extends Pancake{ public abstract String getDesc(); }
鸡蛋(具体装饰者)
package com.study.headfirst.decorator; /** * 鸡蛋(具体装饰者) * @author mdl * @date 2019/12/05 */ public class Egg extends Condiment{ private Pancake cake; public Egg(Pancake cake) { this.cake = cake; } /* (non-Javadoc) * @see com.study.headfirst.decorator.Condiment#desc() */ @Override public String getDesc() { // TODO Auto-generated method stub return cake.getDesc() + ",鸡蛋"; } /* (non-Javadoc) * @see com.study.headfirst.decorator.Pancake#cost() */ @Override public double cost() { // TODO Auto-generated method stub return cake.cost() + 1; } }
火腿(具体装饰者)
package com.study.headfirst.decorator; /** * 火腿(具体装饰者) * @author mdl * @date 2019/12/05 */ public class Ham extends Condiment{ private Pancake cake; public Ham(Pancake cake) { this.cake = cake; } /* (non-Javadoc) * @see com.study.headfirst.decorator.Condiment#desc() */ @Override public String getDesc() { // TODO Auto-generated method stub return cake.getDesc() + ", 火腿"; } /* (non-Javadoc) * @see com.study.headfirst.decorator.Pancake#cost() */ @Override public double cost() { // TODO Auto-generated method stub return cake.cost() + 1.5; } }View Code
生菜(具体装饰者)
package com.study.headfirst.decorator; /** * 生菜(具体装饰者) * @author mdl * @date 2019/12/05 */ public class ShenCai extends Condiment{ private Pancake cake; public ShenCai(Pancake cake) { this.cake = cake; } /* (non-Javadoc) * @see com.study.headfirst.decorator.Condiment#desc() */ @Override public String getDesc() { // TODO Auto-generated method stub return cake.getDesc() + ", 生菜"; } /* (non-Javadoc) * @see com.study.headfirst.decorator.Pancake#cost() */ @Override public double cost() { // TODO Auto-generated method stub return cake.cost() + 0.5; } }View Code
测试
package com.study.headfirst.decorator; /** * @author mdl * @date 2019/12/05 */ public class Test { public static void main(String[] args) { // 点个鸡蛋饼,啥都不加 Pancake cake =new TornCake(); System.out.println(cake.getDesc() + ",价钱:" + cake.cost()); // 点个鸡蛋饼,加两根火腿,加生菜 Pancake cake2 =new TornCake(); cake2 =new Ham(cake2); cake2 =new Ham(cake2); cake2 =new ShenCai(cake2); System.out.println(cake2.getDesc() + ",价钱:" + cake2.cost()); } }