装饰者模式的定义:
装饰者模式:动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
Java实现
借用《Head First设计模式》 中的咖啡店卖咖啡的样例。便于说明,这里简洁一下。假如我要写一个咖啡点单计价的软件。业务逻辑是这样的,一杯咖啡10元,如果加糖另外加1元,如果加奶另外加两元。实际来讲,采用硬编码的方式我可以写三个类来实现该需求:1.咖啡单买;2.咖啡+糖;3.咖啡+奶。然后就完事儿,任务完成。但是如果哪一天,老板打算卖即加糖又加奶的咖啡的话,就得再增加一个类来实现该类型咖啡的计价。这还好说,假如我有多种类型的咖啡呢?而且每种类型的咖啡都可以加奶或者糖,这样排列组合下去,我估计要写吐血…..
下面,我们就使用装饰者模式来解决该问题。
样例
首先来一个咖啡的抽象类
1 2 3 4 5 6 7 8 9 10
| public abstract class AbsCoffee { String description = "Unknown Type";
public String getDescription() { return description; } public abstract double cost(); }
|
接下来两种咖啡的实现
1 2 3 4 5 6 7 8 9 10
| public class MochaCoffee extends AbsCoffee{ public MochaCoffee() { description = "摩卡咖啡"; } @Override public double cost() { return 10; } }
|
1 2 3 4 5 6 7 8 9 10
| public class LatteCoffee extends AbsCoffee{ public LatteCoffee() { description = "拿铁咖啡"; } @Override public double cost() { return 15; } }
|
装饰器
1 2 3 4 5
| public abstract class Decorator extends AbsCoffee { public abstract String getDescription(); }
|
两个装饰类,这里分别为咖啡的调调:糖、牛奶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Sugar extends Decorator{ AbsCoffee coffee; public Sugar(AbsCoffee coffee){ this.coffee = coffee; }
@Override public String getDescription() { return coffee.getDescription()+"+糖"; }
@Override public double cost() { return coffee.cost()+2; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Milk extends Decorator{ AbsCoffee coffee; public Milk(AbsCoffee coffee){ this.coffee = coffee; }
@Override public String getDescription() { return coffee.getDescription()+"+牛奶"; }
@Override public double cost() { return coffee.cost()+1; } }
|
测试结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Test { public static void main(String[] args) { AbsCoffee coffee = new MochaCoffee(); System.out.println(coffee.getDescription()+"="+coffee.cost()); coffee = new Milk(new Sugar(coffee)); System.out.println(coffee.getDescription()+"="+coffee.cost()); } }
|
java.io中的装饰者模式
这里的代码样例来自与《Head First设计模式》一书,演示了FileInputStream中装饰者模式的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in) { super(in); }
public int read() throws IOException { int c = in.read(); return (c == -1 ? c : Character.toLowerCase((char)c)); }
public int read(byte[] b, int offset, int len) throws IOException { int result = in.read(b, offset, len); for (int i = offset; i < offset+result; i++) { b[i] = (byte)Character.toLowerCase((char)b[i]); } return result; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class InputTest { public static void main(String[] args) throws IOException { int c;
try { InputStream in = new LowerCaseInputStream( new BufferedInputStream( new FileInputStream("test.txt")));
while((c = in.read()) >= 0) { System.out.print((char)c); }
in.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
Javascript实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| (function () { function MochaCoffee() { this.description = "摩卡咖啡" } MochaCoffee.prototype.cost = function () { return 10; }; MochaCoffee.prototype.getDescription = function () { return this.description; };
function Sugar(coffee) { this.coffee = coffee; this.description = "糖"; } Sugar.prototype.cost = function () { return this.coffee.cost()+1; }; Sugar.prototype.getDescription = function () { return this.coffee.getDescription()+"+"+this.description }; function Milk(coffee) { this.coffee = coffee; this.description = "牛奶"; } Milk.prototype.cost = function () { return this.coffee.cost()+2; }; Milk.prototype.getDescription = function () { return this.coffee.getDescription()+"+"+this.description };
var coffee = new MochaCoffee(); console.log(coffee.getDescription()+"="+coffee.cost()); coffee = new Milk(new Sugar(coffee)); console.log(coffee.getDescription()+"="+coffee.cost()); })();
|
上一篇:设计模式系列之三观察者模式
下一篇:设计模式系列之五工厂模式
留言
欢迎交流想法。留言会通过 GitHub Issues 保存,首次使用需要登录 GitHub。