扩展系统功能--装饰模式

根据合成复用原则,在实现功能复用时,应该多用关联,少用继承。
装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。
装饰模式是一种用于替代继承的技术,通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。

在装饰模式中,为了让系统具有更好的灵活性和可扩展性,通常会定义一个抽象装饰类,而将具体的装饰类作为它的子类。

屏幕快照 2017-02-22 12.14.31
Component(抽象构件):是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法。它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。

concretecomponent(具体构件类):是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰起可以给它增加额外的职责

Decorator(抽象装饰类):也是抽象构件的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的

ConcreteDecorator(具体装饰类):是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。

由于具体构件类和装饰器类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任

装饰模式的核心在于抽象装饰类的设计

class Decorator implements Component{
    private Comonent component;
    public Decorator(Component component){
        this.component = component;
    }
    public void operation(){
        component.operation();//调用原有的业务方法
    }
}

class ConcreteDecorator extends Decorator{
    public ConcreteDecorator(Component component){
        super(component);
    }
    public void operation(){
        super.operation();
        addedBehavior();
    }
    public void addedBehavior(){
        ...
    }
}

装饰模式虽好,但存在一个问题。如果客户端希望单独调用具体装饰类新增的方法,而不想通过抽象构件中声明的方法来调用新增方法时将遇到问题

Class Decorator implements Document{
    private Document document;
    public Decorator(Document document){
        this.document = document;
    }
    public void display(){
        document.display();
    }
}

class Approver extends Decorator{
    public Approver(Document document){
        super(document);
        System.out.println("add the approver function");
    }
    
    public void approve(){
        System.out.println("approve the file.");
    }
}

Document doc;
doc = new PurchaseRequest();

Approver newDoc = new Approver(doc);
newDoc.display();
newDoc.approve();

如果newDoc也使用Document类型定义,将导致客户端无法调用approve()方法,。也就是说客户端无法统一对待装饰之前的具体构件对象和装饰之后的构件对象。

在实际使用过程中,由于新增行为可能需要单独调用,因此这种形式的装饰模式也经常出现,称为半透明装饰模式

透明装饰模式

在透明装饰模式中,要求客户端完全针对抽象编程。装饰模式的透明性要求客户程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型,对于客户端而言,具体构件对象和具体装饰对象应该没有任何区别。

//应该这样
Component c,c1;
c = new ConcreteComponent();
c1 = new ConcreteDecorator();

//不应该这样
ConcreteComponent c = new ConcreteComponent();
ConcreteDecorator c1 = new ConcreteDecorator();

半透明装饰模式

半透明装饰模式就是使用具体的引用定义。

装饰模式要注意的问题

  1. 尽量保持具体构件类和装饰器类的接口相同。这样对于客户端而言,使用装饰之前和装饰之后的对象就是一样的。也就是说,应该尽量使用透明装饰器
  2. 尽量保持具体构件类ConcreteComponent是一个“轻”类,就是说不要把太多的行为放在具体构件类中,应该尽可能使用装饰器进行扩展
  3. 如果只有一个具体构件类,装饰器可以是这个具体构件类的子类
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值