YAZONG 我的开源

设计模式(九)结构型模式(对象结构型模式)装饰模式-DECORATOR

 
0 评论0 浏览

2、9装饰模式

定义

装饰模式,动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活,或者说是装饰者提供了比继承更有弹性的替代方案。。

通用类图-1

image.png

1)Component抽象构件

Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象,可以给这些对象动态地添加职责。

#在装饰模式中,必然有一个最基本、最核心、最原始的接口或抽象类充当Component抽象构件。

2)ConcreteComponent具体构件

ConcreteComponent是最核心、最原始、最基本的接口或抽象类的实现,就是一个具体的对象,要装饰的就是它,也可以给这个对象添加一些职责。

3)Decorator装饰角色
一般是一个抽象类,作用是实现接口或抽象类Component的方法,它里面可不一定有抽象的方法,在它的属性里必然有一个private变量指向Component抽象构件。但对于Component来说,是无需知道Decorator的存在的。

4)ContreteDecorator具体装饰角色

ContreteDecoratorA和ContreteDecoratorB就是两个具体的装饰对象,起到给Component添加职责的功能。要把最核心的、最原始的、最基本的东西装饰成其他东西。

案例1


public class Client1 {
    public static void main(String[] args) {
        //从上到下依次执行(从外向里拨开,再从里面往外延伸)
        Component component = new ConcreteComponent();
        component = new ConcreteDecorator1(component);
        component = new ConcreteDecorator2(component);
        component.operate();
    }
}

/**
 * 抽象构件
 */
abstract class Component{
    //抽象的方法
    abstract void operate();
}

/**
 * 具体构件
 */
class ConcreteComponent extends Component{
    //具体实现
    @Override
    void operate() {
        System.out.println("具体构件ConcreteComponent-operate()");
    }
}

/**
 * 抽象装饰者
 * 注意:若只有一个装饰者,则可以没有抽象装饰角色,直接实现具体的装饰角色即可。
 */
abstract class Decorator extends Component{

    private Component component = null;
    //通过构造函数传递被修饰者
    public Decorator(Component component) {
        this.component = component;
    }
    //委托给被修饰者执行
    @Override
    void operate() {
        System.out.println("抽象装饰者Decorator-operate() begin");
        this.component.operate();
        System.out.println("抽象装饰者Decorator-operate() end");
    }
}

/**
 * 具体装饰类1
 * 注意:原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序。
 */
class ConcreteDecorator1 extends Decorator{
    //定义被修饰者
    public ConcreteDecorator1(Component component) {
        super(component);
    }
    //定义自己的修饰方法
    public void method1(){
        System.out.println("具体装饰类1-ConcreteDecorator1 method1()");
    }
    //重写父类的operate()方法
    @Override
    void operate() {
        this.method1();
        System.out.println("具体装饰类1-ConcreteDecorator1 operate() begin");
        super.operate();
        System.out.println("具体装饰类1-ConcreteDecorator1 operate() end");
    }
}
/**
 * 具体装饰类2
 * 注意:原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序。
 */
class ConcreteDecorator2 extends Decorator{
    //定义被修饰者
    public ConcreteDecorator2(Component component) {
        super(component);
    }
    //定义自己的修饰方法
    public void method2(){
        System.out.println("具体装饰类2-ConcreteDecorator2 method2()");
    }
    //重写父类的operate()方法
    @Override
    void operate() {
        this.method2();
        System.out.println("具体装饰类2-ConcreteDecorator2 operate() begin");
        super.operate();
        System.out.println("具体装饰类2-ConcreteDecorator2 operate() end");
    }
}

具体装饰类2-ConcreteDecorator2 method2()
具体装饰类2-ConcreteDecorator2 operate() begin
抽象装饰者Decorator-operate() begin
具体装饰类1-ConcreteDecorator1 method1()
具体装饰类1-ConcreteDecorator1 operate() begin
抽象装饰者Decorator-operate() begin
具体构件ConcreteComponent-operate()
抽象装饰者Decorator-operate() end
具体装饰类1-ConcreteDecorator1 operate() end
抽象装饰者Decorator-operate() end
具体装饰类2-ConcreteDecorator2 operate() end

通用类图-2-1

image.png

如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。

案例2-1

public class Client2 {
    public static void main(String[] args) {
        ConcreteComponent component = new ConcreteComponent();
        component = new ConcreteDecorator1(component);
        component = new ConcreteDecorator2(component);
        component.operate();
    }
}


/**
 * 具体构件
 */
class ConcreteComponent {
    //具体实现
    void operate() {
        System.out.println("具体构件ConcreteComponent-operate()");
    }
}

/**
 * 抽象装饰者
 * 注意:若只有一个装饰者,则可以没有抽象装饰角色,直接实现具体的装饰角色即可。
 */
abstract class Decorator extends ConcreteComponent{

    private ConcreteComponent component = null;
    //通过构造函数传递被修饰者
    public Decorator(ConcreteComponent component) {
        this.component = component;
    }
    //委托给被修饰者执行
    @Override
    void operate() {
        System.out.println("抽象装饰者Decorator-operate() begin");
        this.component.operate();
        System.out.println("抽象装饰者Decorator-operate() end");
    }
}

/**
 * 具体装饰类1
 * 注意:原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序。
 */
class ConcreteDecorator1 extends Decorator{
    //定义被修饰者
    public ConcreteDecorator1(ConcreteComponent component) {
        super(component);
    }
    //定义自己的修饰方法
    public void method1(){
        System.out.println("具体装饰类1-ConcreteDecorator1 method1()");
    }
    //重写父类的operate()方法
    @Override
    void operate() {
        this.method1();
        System.out.println("具体装饰类1-ConcreteDecorator1 operate() begin");
        super.operate();
        System.out.println("具体装饰类1-ConcreteDecorator1 operate() end");
    }
}
/**
 * 具体装饰类2
 * 注意:原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序。
 */
class ConcreteDecorator2 extends Decorator{
    //定义被修饰者
    public ConcreteDecorator2(ConcreteComponent component) {
        super(component);
    }
    //定义自己的修饰方法
    public void method2(){
        System.out.println("具体装饰类2-ConcreteDecorator2 method2()");
    }
    //重写父类的operate()方法
    @Override
    void operate() {
        this.method2();
        System.out.println("具体装饰类2-ConcreteDecorator2 operate() begin");
        super.operate();
        System.out.println("具体装饰类2-ConcreteDecorator2 operate() end");
    }
}


具体装饰类2-ConcreteDecorator2 method2()
具体装饰类2-ConcreteDecorator2 operate() begin
抽象装饰者Decorator-operate() begin
具体装饰类1-ConcreteDecorator1 method1()
具体装饰类1-ConcreteDecorator1 operate() begin
抽象装饰者Decorator-operate() begin
具体构件ConcreteComponent-operate()
抽象装饰者Decorator-operate() end
具体装饰类1-ConcreteDecorator1 operate() end
抽象装饰者Decorator-operate() end
具体装饰类2-ConcreteDecorator2 operate() end

通用类图-2-2

image.png

同样的道理,如果只有一个ContreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ContreteDecorator的责任合并成一个类。

案例2-2

public class Client3 {

    public static void main(String[] args) {

        Component component = new ConcreteComponent();

        component = new ConcreteDecorator1(component);

        component.operate();

    }

}

 

/**

 * 抽象构件

 */

abstract class Component{

    //抽象的方法

    abstract void operate();

}

 

/**

 * 具体构件

 */

class ConcreteComponent extends Component{

    //具体实现

    @Override

    void operate() {

        System.out.println("具体构件ConcreteComponent-operate()");

    }

}

 

/**

 * 具体装饰类1

 * 注意:原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序。

 */

class ConcreteDecorator1 extends Component{

 

    private Component component = null;

    //通过构造函数传递被修饰者

    public ConcreteDecorator1(Component component) {

        this.component = component;

    }

    //定义自己的修饰方法

    public void method1(){

        System.out.println("具体装饰类1-ConcreteDecorator1 method1()");

    }

    //重写父类的operate()方法

    @Override

    void operate() {

        this.method1();

        System.out.println("具体装饰类1-ConcreteDecorator1 operate() begin");

        this.component.operate();

        System.out.println("具体装饰类1-ConcreteDecorator1 operate() end");

    }

}

 

具体装饰类1-ConcreteDecorator1 method1()

具体装饰类1-ConcreteDecorator1 operate() begin

具体构件ConcreteComponent-operate()

具体装饰类1-ConcreteDecorator1 operate() end

使用场景

描述

1)需要扩展一个类的功能,或给一个类增加附加功能。

2)需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

3)需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式。

IO流类图

image.png

IO流案例

public class Client4 {

    public static void main(String[] args) {

        int c;

        try {

            InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("D:\\text\\test.txt")));

            while ((c = in.read()) >= 0){

                System.out.println((char)c);

            }

            in.close();

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}

class LowerCaseInputStream extends FilterInputStream{

    protected LowerCaseInputStream(InputStream in) {

        super(in);

    }

 

    @Override

    public int read() throws IOException {

        int c = super.read();

        return (c == -1 ? c : Character.toLowerCase((char)c));

    }

 

    @Override

    public int read(byte[] b, int offset, int len) throws IOException {

        int result = super.read(b, offset, len);

        for(int i = offset;i < offset + result;i++){

            b[i] = (byte)Character.toLowerCase((char)b[i]);

        }

        return result;

    }

}

优点

1)装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说,Component类无须知道Decorator类,Decorator类是从外部来扩展Component类的功能,而Decorator也不用知道具体的构件。

2)装饰模式是继承关系的一个替代方案。我们看装饰类Decorator,不管装饰多少层,返回的对象还是Component,实现的还是is-a关系。

3)装饰模式可以动态地扩展一个实现类的功能。

4)有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑。

缺点

多层的装饰是比较复杂的(不只需要实例化组件,还要把此组件包装进装饰者中)。想想看,就像剥洋葱一样,剥到了最后才发现最里层的装饰出现了问题,想象下工作量吧,因此,尽量减少装饰类的数量,以便降低系统的复杂度。

要点

1)继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式。

2)在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码。

3)组合和委托可用于在运动时动态地加上新的行为。

4)除了继承,装饰者模式也可以让我们扩展行为。

5)装饰者模式意味着一群装饰者类,这些类用来包装具体组件。

6)装饰者反映出被装饰的组件类型(事实上,它们具有相同的类型,都经过接口或继承实现)。

7)装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。

8)你可以用无数个装饰者包装一个组件。

9)装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。

10)装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。


标题:设计模式(九)结构型模式(对象结构型模式)装饰模式-DECORATOR
作者:yazong
地址:https://blog.llyweb.com/articles/2020/06/23/1592844489392.html