《head first设计模式》之装饰者模式理解

  • 定义:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,在不改变原来代码的情况下,扩展功能。

  • 设计原则:开闭原则,对扩展开放,对修改关闭。

  • 举个栗子:

    星巴克有很多种咖啡,有很多种调料,目的是为了计算最终的价格cost方法(添加调料后)和此种咖啡的描述getDesp方法(咖啡名+调料1+调料2),这里引申出来的问题是如何动态的添加调料,在不修改原来代码的情况下计算。到这里,我们可以想想一下代码结构了,首先有一个咖啡类,他是个父类,里面有cost和getDesp方法,若干个子类继承此类重写实现。

  • 想当然的做法:

    如果按照web系统开发的思维方法,再有持久层的时候,我们可以把咖啡作为一个实体对象,调料呢可以是一个字典(id,名字,价格),想象一下,你在网页上有多个select下拉框,这里把调料都展示出来,用户要什么就选中什么,后面再有个输入框是数量,而咖啡则与调料则是一对多关系,在实体中有个map体现,key为调料的id,value为数量,而计算价格和描述呢,遍历这个map就可以了,这是贼舒服。

  • 分析:

    可是为啥还要用这个装饰着模式来解决?我认为学习设计模式,看懂这个模式的代码贼简单,关键是要理解他为什么这么干,当他提出问题的场景时,我们先自己考虑一种做法,再与真正的模式作比较,思考模式带来的好处。那么上面提出的想当然做法,其实也挺好啊,与模式比较,谁对说错呢?其实首先我们进入了一个误区,用设计模式 不该考虑持久化的事情,应该用单纯的javase解决问题。从持久化来看,我们调料是一个类,有若干条数据,如果不用持久化,则我们每一个调料都是一个类,然后咖啡持有一个list调料的集合,往里面add,遍历这个list即可了,与持久化相比不过是每条数据算一个类罢了,这样可不可以呢???其实在咖啡计算这个场景下是可以的,但是这里我们只是简单的计算功能,这里调料类不过起到了存储数据的作用,如果功能更复杂了呢?需要多行代码处理一些其他的事情?回到上面的问题,如何在不修改原来代码,动态扩展功能(添加调料,计算价格),此为开闭原则。

  • 术语:组件(相当于咖啡),装饰者(相当于调料)

  • 本人总结:

    装饰者要扩展原来组件的功能,怎么扩展?说白了:装饰者要持有组件对象,装饰者有一个方法对应扩展组件中的一个方法。怎么理解:要扩展原来对象的功能,我首先得有原来对象啊,所以我用一个成员变量持有原来对象,我再有个扩展方法 扩展 组件中需要扩展的方法,前提是这个需要扩展的方法,是有返回值的,他不可能是void啊,因为我需要对他TA个值再进行二次的处理啊,这才叫扩展啊。这个道理很容易理解,其实这里扮演装饰者的角色,你当然可以在任何一个类,方法中都可以做到,但那怎么还称之为模式啊,这里装饰者类是只做这个事情,只与原来组件相关,他是不耦合任何其他操作的。模式是有固定的抽象层面的套路,这里的套路是组件有个父类,组件中需要变化的方法在父类中,由子类重写,而装饰者是为了扩展这些变化的方法,所以装饰者直接或间接也继承组件父类,并持有组件父类引用。

    值得注意的是,java中io是用了装饰者模式,这就不难理解为什么有的io类构造方法是传入另一个io类。

  • UML:

  • 代码:

public abstract class AbstractCoffee {
    String name = "unknown coffee";

    public String getName() {
        return name;
    }

    public abstract double cost();
}
public class ACofffee extends AbstractCoffee {
    public ACofffee() {
        name = "A";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}
public class BCoffee extends AbstractCoffee {

    public BCoffee() {
        name = "B";
    }

    @Override
    public double cost() {
        return 0.99;
    }
}
public class Mocha extends AbstractCoffee {
    private AbstractCoffee abstractCoffee;

    public Mocha(AbstractCoffee abstractCoffee) {
        this.abstractCoffee = abstractCoffee;
    }

    @Override
    public double cost() {
        return abstractCoffee.cost() + 0.2;
    }

    @Override
    public String getName() {
        return abstractCoffee.getName() + ",Mocha";
    }
}
    public static void main(String[] args) {
        AbstractCoffee coffee = new ACofffee();
        coffee = new Mocha(coffee);
        coffee = new Mocha(coffee);
        System.out.println(coffee.cost());
    }
结果:`2.39`

转载于:https://my.oschina.net/wecanweup/blog/2872175

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值