23种设计模式—— 装饰者设计模式

定义

  23种设计模式之一,英文叫Decorator Pattern,又叫包装模式。装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。

特点

  1. 装饰对象和真实对象有相同的接口。
  2. 装饰对象包含一个真实对象的引用。
  3. 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象
  4. 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

场景模拟

模拟冰淇淋店订单系统的案例:
冰淇淋种类:MilkCream、ChocolateCream、StrawberryCream、MixCream
配料种类:Candy、Fruit、Jam

一、利用oop思想设计方案:
1. 为所用冰淇淋类抽象出一个父类:IceCream,类中有私有成员变量description与getDescription()方法,抽象方法cost(),分别作为获取冰淇淋描述与价格的方法。
2. 所有冰淇淋类继承IceCream,分别定义其description与cost()方法。
3. 继续定义配料与冰淇淋组合的类:MilkCream&&CandyMilkCream&&FruitMilkCream&&Candy&&Fruit…. 重新定义冰淇淋描述与价格的方法。
总结:设计到这里发现问题,若只需冰淇淋单品类的话可以接受,一旦配合配料一起设计类,发现需要创建的类too many…进而利用装设者模式改进此问题。

二、改进设计方案:

  1. 为所用冰淇淋类抽象出一个父类:IceCream,类中有私有成员变量description,与私有成员变量candy、fruit、jam,描述配料的信息。
    有成员方法cost()与私有成员变量的set(),get()方法,在getDescription()中判断candy、fruit、jam的状态
  2. 所有冰淇淋类继承IceCream
    这里写图片描述
    总结:此种方案可以通过判断candy、fruit、jam的状态来获取是否加入该配料的信息,例如-1代表未条件该配料,正数代表添加了几分,解决了上个方案类爆炸的问题,但仍存在隐患,例如新加入一种配料的话,需要在已经设计好的类中继续修改程序,违反了程序设计中的开放-关闭原则,仍不理想。

三、利用装饰者设计模式设计方案:

  1. 设计所有类的超类Ice:
/*
 * 所有类的超类,冰淇淋类配料类均继承此类
 */
public abstract class Ice {
    //冰激凌或配料的描述
    private String description = "";
    //价格
    private double price;

    public String getDescription() {
        return description+"  价格:"+this.price;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
    public abstract double cost();
}

2.由于所有冰淇淋类中的cost()方法均为返回此价格,进而继续为所有冰淇淋类再次抽象出一个父类IceCream

public class IceCream extends Ice {

    @Override
    public double cost() {
        return this.getPrice();
    }

}

3.创建各个冰淇淋类

/*
 * 牛奶冰淇淋!
 */
public class MilkCream extends IceCream {

    public MilkCream(){
        super.setDescription("牛奶冰淇淋!");
        super.setPrice(3.5);
    }

}


/*
 * 巧克力冰淇淋!
 */
public class ChocolateCream extends IceCream {

    ChocolateCream() {
        super.setDescription("巧克力冰淇淋!");
        super.setPrice(5);
    }
}


/*
 * 草莓冰淇淋!
 */
public class StrawberryCream extends IceCream {

    StrawberryCream() {
        super.setDescription("草莓冰淇淋!");
        super.setPrice(4);

    }

}


/*
 * 什锦冰淇淋
 */
public class MixCream extends IceCream  {

    public MixCream(){
        super.setDescription("什锦冰淇淋");
        super.setPrice(6);
    }
}

4.创建一个配料类Seasoning

public class Seasoning extends Ice {
    private Ice Obj;  //待装饰的对象

    public Seasoning(Ice Obj){
        this.Obj=Obj;
    };

    @Override
    public double cost() {
        return super.getPrice()+Obj.cost();
    }
    @Override
    public String getDescription()
    {
        return super.getDescription()+"+"+Obj.getDescription();
    }
}

5.创建各个配料类

/*
 * 配料:糖果
 */
public class Candy extends Seasoning {
    public Candy(Ice obj){
        super(obj);
        super.setDescription("糖果");
        super.setPrice(2.0);
    }

}

/*
 * 配料:水果粒
 */
public class Fruit extends Seasoning  {

    public Fruit(Ice Obj) {
        super(Obj);
        super.setDescription("水果粒");
        super.setPrice(2.5);
    }

}

/*
 * 配料:果酱
 */
public class Jam extends Seasoning  {

    public Jam(Ice Obj) {
        super(Obj);
        super.setDescription("果酱");
        super.setPrice(1.5);
    }

}

6.创建测试类IceShop,模拟订单系统

/*
 * 冰淇淋商店类
 */
public class IceShop {

    public static void main(String[] args) {
        Ice ice;
        ice = new MilkCream();
        System.out.println("ice1 价格:"+ice.cost());
        System.out.println("ice1 描述:"+ice.getDescription());

        System.out.println("---------------------------------------");
        ice = new MixCream();
        ice = new Candy(ice);
        ice = new Fruit(ice);
        ice = new Jam(ice);

        System.out.println("ice2 价格:"+ice.cost());
        System.out.println("ice2 描述:"+ice.getDescription());
    }

}

7.结果
这里写图片描述
8.图形模拟
这里写图片描述

优缺特点

  1. 装饰者模式与继承关系的目的都是要扩展对象的功能,但是装饰者可以提供比继承更多的灵活性。
  2. 使用不同的具体类与装饰类的排列组合,可以在不改变原有的基础上创造出很多不同行为的组合。
  3. 对比继承而言,代码更复杂。

适用场景

1.某个已有的对象添加新功能时
2.设计某个状态经常需要改动的对象时

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值