设计模式之装饰模式
2017-02-08 12:01
363 查看
装饰模式定义:装饰模式动态的将责任附加到对象上,若要扩展功能,装饰模式提供了比继承更有弹性的替代方案
看下下面的例子,总共有两种咖啡:Decaf、Espresso,另有两种调味品:Mocha、Whip(3种设计的主要差别在于抽象方式不同)
设计一:
即使添加在多的调味品,咖啡依然是咖啡,在抽象的过程中并没有考虑咖啡和调味品之间的关系
当咖啡和调味品的种类很多时,将会产生大量的类,如果一种咖啡的价格发生变动,需要找到所有相关的类逐一修改
设计二:
将调味品作为Coffee类的属性,比起设计一,类的数量大大减少,相应的,程序结构也更加清晰
[java] view
plain copy
public class Coffee {
private boolean mocha;
private boolean whip;
public double cost(){
double price = 0d;
if(mocha){
price += 0.5;
}
if(whip){
price += 0.1;
}
return price;
}
public void addMocha(){
this.mocha = true;
}
public void addWhip(){
this.whip = true;
}
}
[java] view
plain copy
public class Decaf extends Coffee{
public double cost(){
double price = super.cost();
price += 2.0;
return price;
}
}
[java] view
plain copy
public class Espresso extends Coffee {
public double cost(){
double price = super.cost();
price += 2.5;
return price;
}
}
测试一下:
[java] view
plain copy
public class Test {
public static void main(String[] args) {
Coffee coffee = new Decaf();
coffee.addMocha();
coffee.addWhip();
//2.6
System.out.println(coffee.cost());
}
}
考虑到下面几个问题,设计二有明显的不足:
1,如果调味品的种类较多,Coffee类将会变得相当庞大,难以维护
2,无法处理顾客希望添加双倍的Mocha的场景
3,添加一种新的咖啡IceCoffee,从逻辑上来说IceCoffee是不能加Mocha的,但是由于IceCoffee类继承自Coffee类,IceCoffee类依然从父类继承了addMocha()方法,这就需要在IceCoffee类中重写一个空的addMocha()方法,并且当使用IceCoffee类时,不能够面向Coffee类编程,以避免错误的调用父类方法
设计三--装饰器模式:
装饰模式分为3个部分:
1,抽象组件 -- 对应Coffee类
2,具体组件 -- 对应具体的咖啡,如:Decaf,Espresso
3,装饰者 -- 对应调味品,如:Mocha,Whip
装饰模式有3个特点:
1,具体组件和装饰者都继承自抽象组件(Decaf、Espresson、Mocha和Whip都继承自Coffee),并且装饰者持有抽象组件的引用
2,可以使用装饰者组合具体组件创造出新的类(Mocha组合Decaf创造出MochaDecaf)
3,过程2可以重复,直到创造出需要的类
使用装饰模式,想要获得一个WhipDoubleMochaEspresso是很容易的:
[java] view
plain copy
public interface Coffee {
public double cost();
}
[java] view
plain copy
public class Espresso implements Coffee {
public double cost(){
return 2.5;
}
}
[java] view
plain copy
public class Dressing implements Coffee {
private Coffee coffee;
public Dressing(Coffee coffee){
this.coffee = coffee;
}
public double cost(){
return coffee.cost();
}
}
[java] view
plain copy
public class Whip extends Dressing {
public Whip(Coffee coffee){
super(coffee);
}
public double cost(){
return super.cost() + 0.1;
}
}
[java] view
plain copy
public class Mocha extends Dressing {
public Mocha(Coffee coffee){
super(coffee);
}
public double cost(){
return super.cost() + 0.5;
}
}
测试一下:
[java] view
plain copy
public class Test {
public static void main(String[] args) {
Coffee coffee = new Espresso();
coffee = new Mocha(coffee);
coffee = new Mocha(coffee);
coffee = new Whip(coffee);
//3.6(2.5 + 0.5 + 0.5 + 0.1)
System.out.println(coffee.cost());
}
}
当然Decorator类中可以重写父类的方法,也可以扩展自己需要的方法
装饰模式的缺点:
1,装饰模式虽然扩展性较高,但是没有设计二简洁,类的数量略多(但肯定比设计一少很多),如何取舍可扩展性和简洁性是个问题,有所选择就要有所牺牲
2,很难搞清楚一个类究竟被装饰了多少层,可能是1层,也可能是100层
看下下面的例子,总共有两种咖啡:Decaf、Espresso,另有两种调味品:Mocha、Whip(3种设计的主要差别在于抽象方式不同)
设计一:
即使添加在多的调味品,咖啡依然是咖啡,在抽象的过程中并没有考虑咖啡和调味品之间的关系
当咖啡和调味品的种类很多时,将会产生大量的类,如果一种咖啡的价格发生变动,需要找到所有相关的类逐一修改
设计二:
将调味品作为Coffee类的属性,比起设计一,类的数量大大减少,相应的,程序结构也更加清晰
[java] view
plain copy
public class Coffee {
private boolean mocha;
private boolean whip;
public double cost(){
double price = 0d;
if(mocha){
price += 0.5;
}
if(whip){
price += 0.1;
}
return price;
}
public void addMocha(){
this.mocha = true;
}
public void addWhip(){
this.whip = true;
}
}
[java] view
plain copy
public class Decaf extends Coffee{
public double cost(){
double price = super.cost();
price += 2.0;
return price;
}
}
[java] view
plain copy
public class Espresso extends Coffee {
public double cost(){
double price = super.cost();
price += 2.5;
return price;
}
}
测试一下:
[java] view
plain copy
public class Test {
public static void main(String[] args) {
Coffee coffee = new Decaf();
coffee.addMocha();
coffee.addWhip();
//2.6
System.out.println(coffee.cost());
}
}
考虑到下面几个问题,设计二有明显的不足:
1,如果调味品的种类较多,Coffee类将会变得相当庞大,难以维护
2,无法处理顾客希望添加双倍的Mocha的场景
3,添加一种新的咖啡IceCoffee,从逻辑上来说IceCoffee是不能加Mocha的,但是由于IceCoffee类继承自Coffee类,IceCoffee类依然从父类继承了addMocha()方法,这就需要在IceCoffee类中重写一个空的addMocha()方法,并且当使用IceCoffee类时,不能够面向Coffee类编程,以避免错误的调用父类方法
设计三--装饰器模式:
装饰模式分为3个部分:
1,抽象组件 -- 对应Coffee类
2,具体组件 -- 对应具体的咖啡,如:Decaf,Espresso
3,装饰者 -- 对应调味品,如:Mocha,Whip
装饰模式有3个特点:
1,具体组件和装饰者都继承自抽象组件(Decaf、Espresson、Mocha和Whip都继承自Coffee),并且装饰者持有抽象组件的引用
2,可以使用装饰者组合具体组件创造出新的类(Mocha组合Decaf创造出MochaDecaf)
3,过程2可以重复,直到创造出需要的类
使用装饰模式,想要获得一个WhipDoubleMochaEspresso是很容易的:
[java] view
plain copy
public interface Coffee {
public double cost();
}
[java] view
plain copy
public class Espresso implements Coffee {
public double cost(){
return 2.5;
}
}
[java] view
plain copy
public class Dressing implements Coffee {
private Coffee coffee;
public Dressing(Coffee coffee){
this.coffee = coffee;
}
public double cost(){
return coffee.cost();
}
}
[java] view
plain copy
public class Whip extends Dressing {
public Whip(Coffee coffee){
super(coffee);
}
public double cost(){
return super.cost() + 0.1;
}
}
[java] view
plain copy
public class Mocha extends Dressing {
public Mocha(Coffee coffee){
super(coffee);
}
public double cost(){
return super.cost() + 0.5;
}
}
测试一下:
[java] view
plain copy
public class Test {
public static void main(String[] args) {
Coffee coffee = new Espresso();
coffee = new Mocha(coffee);
coffee = new Mocha(coffee);
coffee = new Whip(coffee);
//3.6(2.5 + 0.5 + 0.5 + 0.1)
System.out.println(coffee.cost());
}
}
当然Decorator类中可以重写父类的方法,也可以扩展自己需要的方法
装饰模式的缺点:
1,装饰模式虽然扩展性较高,但是没有设计二简洁,类的数量略多(但肯定比设计一少很多),如何取舍可扩展性和简洁性是个问题,有所选择就要有所牺牲
2,很难搞清楚一个类究竟被装饰了多少层,可能是1层,也可能是100层
相关文章推荐
- 设计模式---装饰模式
- NET设计模式之一:装饰模式(Decorator Pattern)
- 设计模式中结构型模式(四)装饰模式(Decorator)
- 设计模式c#描述——装饰(Decorator)模式
- 第四个设计模式:装饰模式
- 设计模式c#语言描述——装饰(Decorator)模式
- 结构型设计模式---Decorator模式(装饰模式)
- .NET设计模式研究之装饰模式
- 解读设计模式----装饰模式(Decorator Pattern)
- 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern)
- 用实例解说Dot Net设计模式——装饰模式
- 第四个设计模式:装饰模式
- AspectJ实现设计模式(七)—装饰模式
- 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern)
- 设计模式之---装饰(decorator)
- 设计模式c#语言描述——装饰(Decorator)模式
- 设计模式之装饰模式篇(Decorator)
- 设计模式之--装饰器模式的硬编码的静态装饰和链化
- 设计模式学习笔记-装饰模式
- 设计模式(11)-装饰模式(Decorator)