设计模式之装饰者模式

一、概述

为什么需要装饰者模式?在不允许直接修改原代码的情况下进行扩展时需要使用装饰者模式。装饰者模式动态的将责任(行为)附加到对象身上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。 这就是设计中的开放——关闭原则,对扩展开放,对修改关闭。以下时关于装饰者模式的一些相关特征:

  1. 装饰者与被装饰者拥有相同的超类
  2. 可以用一个或多个装饰者去包装一个对象
  3. 装饰者和被装饰者拥有相同的超类,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象来替代它
  4. 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
  5. 对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的使用装饰者来装饰对象。

二、例

我们都知道,一个专业中包括主修课程和选修课程,主修课程和选修课程都是可以获得学分的,而一般来说主修课程就体现了一个专业的类型(是哪个专业)。现在就通过这个例子使用装饰者模式来实现一下这种情况。

其中会包括超类/最高级接口、组件(被装饰者)、装饰者。那么超类/最高级接口就应该是专业,组件就应该是专业中的主修课程,装饰者就应该是专业中的选修课程。前面说过:装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。这里面是通过选修课程获得学分,以达到专业允许毕业学分和专业组成的目的。

超类(专业):

package decorator2;

/**
 * 装饰者模式中的超类(专业)
 */
public abstract class AbstractMajor {

    String description = "Unknown Subject";

    /**
     * 学科描述
     * @return
     */
    public String getDescription() {
        return description;
    }

    /**
     * 可获得的学分
     * @return
     */
    public abstract double cost();
}

组件(BiologySubject主修生物学-----被装饰者):

package decorator2;

/**
 * 主修生物学
 */
public class BiologySubject extends AbstractMajor {

    public BiologySubject() {
        description = "主修学科:Biology";
    }

    /**
     * 学分计算
     * @return
     */
    @Override
    public double cost() {
        return 1;
    }
}

装饰者共同实现的接口或继承的抽象类:

package decorator2;

/**
 * 选修课
 */
public abstract class AbstractElectiveSubject extends AbstractMajor {

    @Override
    public abstract String getDescription();
}

装饰者A:

package decorator2;

/**
 * 英语选修
 */
public class EnglishSubject extends AbstractElectiveSubject {

    /** 学科 */
    AbstractMajor abstractSubject;

    public EnglishSubject(AbstractMajor abstractSubject) {
        this.abstractSubject = abstractSubject;
    }

    @Override
    public String getDescription() {
        return abstractSubject.getDescription() + "  选修English";
    }

    @Override
    public double cost() {
        return 2 + abstractSubject.cost();
    }
}

装饰者B:

package decorator2;

/**
 * 高数选修
 */
public class MathematicsSubject extends AbstractElectiveSubject {

    /** 学科 */
    AbstractMajor abstractSubject;

    public MathematicsSubject(AbstractMajor abstractSubject) {
        this.abstractSubject = abstractSubject;
    }

    @Override
    public String getDescription() {
        return abstractSubject.getDescription() + "  选修:mathematics";
    }

    @Override
    public double cost() {
        return 3 + + abstractSubject.cost();
    }
}

测试类:

package decorator2;

public class Test {
    public static void main(String[] args) {
        AbstractMajor abstractSubject = new BiologySubject();
        abstractSubject = new MathematicsSubject(abstractSubject);
        abstractSubject = new EnglishSubject(abstractSubject);
        System.out.println(abstractSubject.getDescription() + "  学分共:" + abstractSubject.cost());
    }
}

测试结果就不粘贴了,各位看官可以自己尝试。

前面由提到,装饰者提供了比继承更有弹性的解决方案,但是在代码中都是使用了继承,代码我们使用继承是达到了“类型匹配”的效果,而不是通过继承来获得行为(方法),就像前面提到的“装饰者与被装饰者拥有相同的超类”,这里面组件(专业)获得新的行为(学科)是通过组合对象获得的,不是通过继承获得的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值