一文理解Java设计中装饰模式,从理论到实践

2dfefbb35cf151b39b49ef98c1b06efb.png

点击上方“蓝字”关注我们

5b68c02a401e84bc2c496299d9914ef0.png

一、概述

3f7a1ee47fab8b562647a3db48c650fc.png

(1)动态地给一个对象增加一些额外的职责(方法)。就扩展功能而言,装饰者模式提供了一种比使用子类更加灵活的替代方案。

(2)装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。

baf4475de982c46f8514ce8197767cda.png

2a060cf29e534ba68a62dcaa09ef1e80.png

ca5565b661a55f020a15bf2362a80dc9.png

二、结构与实现

df3004a1a8e5989140871bb9c324f011.png

(1)结构:

1、Component(抽象构件):是具体构件类和抽象装饰者类的共同父类。

2、ConcreteComponent(具体构件类):抽象构件的子类,装饰者类可以给它增加额外的职责。

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

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

5bdf548e3aaf3b7b2101230267942cf1.png

6fd6331372ea0155ca9382d8e3f51dba.png

b539032ac0e451ad4c6f738e8897b9d7.png

e9b75293650f64ed927be594b9e39318.png

fd16b84045b19d91e76890884bf67877.png

4c4f7d48bfef42706b284284057cde2f.png

1f1f808300c365e90583adffee94f10f.png

c7feb45b5906768053d0cfcb454e6ebf.png

(2)实现

458eb8ab36fb5c54ccb6b8fcfb874de8.png

efaeeb4a6de456ba06ce12ba01cab62b.png

abstract class Component{
  abstract void operation();
}

class ConcreteComponent extends Component{
  void operation(){
    //功能实现
  }
}

class Decorator extends Component{
  private Component 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(){
    //新增业务方法
  }
}

bf03a6156b8bb1e58b037705f1eabb04.png

三、应用案例

885b6df8fef732b112f8e7145a087947.png

061e4cc93060781959346ab7c582b15d.png

5afab7b9e40638d11401c37aaa616835.png

aece298e02963eef5c38667a19f9d186.png

6aae8d566b357fc47a33d769a8f84163.png

22ed49aa3167960490acf6719aa39dcf.png

(1)分析:窗体、文本框、列表框为具体构件类,滚动条、黑色边框为具体装饰类。

9b732af854bdccba108874791722ac56.png

6cd66b57ef4d1851fd8856e31dc6112b.png

5ea017e84762d90ecce854bc50fa3b3d.png

(2)类图设计

cc7c23447e6cec0606429b26520d7f48.png

04ffbcf9bf1fd0b2547a830294e32b46.png

3e5d9812aa6b169aaececd514a7fbb7a.gif

799b33c924fb01debfb1b98fe0df88f2.png

eea60b07c463177fa1e34ad2be7ef7d9.png

ee30d87f0b955aca61023355e354c5a6.png

3fb5e1fcbf522c0db3cdc37500ed32d6.png

d92715de7d8339a10fc0abf384c928eb.png

(3)实现

cc61b35a8599668a1e72083c9b27f728.png

a8dfb62b962de64e8de37883a5afeaec.png

//抽象构件类
abstract class Component {
    public abstract void display();
}
//具体构件类(抽象构件类子类)
class ListBox extends Component {
    @Override
    public void display() {
        System.out.println("显示列表框...");
    }
}
class TextBox extends Component {
    @Override
    public void display() {
        System.out.println("显示文本框...");
    }
}
class Window extends Component {
    @Override
    public void display() {
        System.out.println("显示窗体...");
    }
}

//抽象装饰类(抽象构件子类)
class ComponentDecorator extends Component{
    private Component component;
    public ComponentDecorator(Component component){
        this.component=component;
    }
    @Override
    public void display() {
        component.display();
    }
}

//具体装饰者类(抽象装饰子类)
class BlackBorderDec extends ComponentDecorator {
    public BlackBorderDec(Component component) {
        super(component);
    }
    public void display(){
        this.setBlackBorder();
        super.display();
    }
    private void setBlackBorder() {
        System.out.println("添加了黑色边框...");
    }
}
class ScrollBarDec extends ComponentDecorator {
    public ScrollBarDec(Component component) {
        super(component);
    }
    public void display(){
        this.setScrollBar();
        super.display();
    }
    private void setScrollBar() {
        System.out.println("添加了滚动条...");
    }
}

//模拟客户端测试
public class client {
    public static void main(String[] args) {
        Component component1=new Window();
        Component comB=new ScrollBarDec(component1);
        Component comBB=new BlackBorderDec(comB);
        comWithBlack.display();
    }
}

8e3d83ee066d00a5f1bd75cd6292ef98.png

(4)测试结果及发现:将装饰一次之后的comB对象再次注入另一个具体装饰类,实现第二次装饰,得到了一个经过两次装饰的comBB对象,再调用display()方法就可以得到一个既有滚动条又有黑色边框的窗体了。

01c9e7edaf24e0f5d2d0b8744bf5fc2a.png

6bb1e0e5770c20aab7682d4c3a9de3ca.png

ce525a7dceb5128d0accf24354b23f3f.gif

b96e507b0b757d0b7696eac84b6400c7.png

059dcb4a653d3abdca771ec8469f56c3.png

d1412fb7d63bffb3c65ae64a8cadb9c7.png

86741795880bce5cce26a1680a5152cb.png

2ffb3f10338b5cbdc51dba9c6780570f.png

四、扩展

aaab8be5827e4ebf27e63f2f54fc6f06.png

(1)透明装饰模式:在透明装饰模式中要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型。对客户端而言,具体构件类和具体装饰类对象没有任何区别。(缺点,无法单独调用装饰类的独有功能)

381ba7b04165028b9ccafb360eae100a.png

234e61f3013832a4760be708cfbdb7a4.png

//不应该将对象声明为具体构件类型或具体装饰者类型
  Window window=new Window();
  //应该声明为抽象构件类型,向上转型
  Component window=new Window();

82db80cef90785e99b6896de344a017f.png

(2)半透明装饰模式:用具体装饰类型来定义装饰后的对象,而具体构件类型仍然可以使用抽象构件类型来定义,可以单独调用装饰的独有方法。(缺点:无法多次进行装饰)

c6b91bc9bf9ba2bf47f971ca758886d9.png

8d8c19dbda894be4bcfe0eb1b626b929.png

//具体构件类型仍然可以使用抽象构件类型来定义
  Component window =new Window();
  //具体装饰类型来定义装饰后的对象
  BlackBorderDec blackBorder=new BlackBorderDec(window);
  //可以单独调用
  blackBorder.setBlackBorder();

edd0849cd49553b74384c55792627d84.png

五、总结

4596d5d95f284ffeb414f0770e109a8b.png

(1)特点:

(A)可以动态增加或删除对象的职责,并使需要装饰的具体构件类和具体装饰类可以独立变化,以便增加新的具体构件类和具体装饰类。

(B)减少子类个数,扩展方便,容易维护。

(C)结构主要有抽象构件类,其子类有具体构件类和抽象装饰类,而在抽象装饰类中,其子类则是具体装饰类。

1a5e5a564f6e782a1103055d21d4a776.png

b0d250b0f10999fd73bc8f8f33ea5e41.png

a1107d5df37145bd497f7a2cbb0f473d.png

(2)适用环境:

(A)在不影响其他对象的情况下以动态透明的方式给单个对象添加职责。

(B)当不能采用继承的方式时。主要有两种情况:子类大爆炸,类已经被定义为不能继承。

02b140245687484598c0db95057d35c2.png

2381975c01fbeaf8b77931636b2e692a.png

6e607282c71c64724f42a4596d1d4c85.png

e9d6bf0c6638677aaf2b5041bc77f226.png

扫码二维码

获取更多精彩

IT学习小镇

9bf71ecccf24f4a60fa7eb4d556da1e6.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值