乐趣区

关于设计模式:设计模式学习笔记十二装饰模式

1 概述

1.1 引言

装璜模式能够在不扭转一个对象自身性能的根底上给对象减少额定的新行为。比方,一张照片,不扭转照片自身,减少一个相框。

装璜模式是一种用于代替继承的技术,毋庸定义子类即可给对象动静减少职责,应用对象之间的关联关系来代替继承关系,在装璜模式中引入了装璜类,在装璜类中既能够调用待装璜的原有类办法,还能够减少新的办法,以裁减原有的类性能。

1.2 定义

装璜模式:动静地给对象减少一些额定的职责。

就减少对象性能来说,装璜模式比生成子类实现更为灵便,装璜模式是一种对象结构型模式。

1.3 结构图

1.4 角色

  • Component(形象构件类):是具体构件以及形象装璜类的父类,申明了在具体构件中实现的业务办法,它的引入能够使客户端以统一的形式解决未被装璜之后的对象,以实现客户端的通明操作
  • ConcreteComponent(具体构件类):是形象构件类的子类,用于定义具体的构件对象,实现了在形象构件中申明的办法,装璜器能够给它减少额定的职责
  • Decorator(形象装璜类):用于给具体构件类减少职责,然而具体职责在子类实现。形象装璜类保护一个指向形象构件的援用,通过该援用能够调用装璜之前构件对象的办法,并通过子类扩大该办法以达到装璜的目标
  • ConcreteDecorator(具体装璜类):负责向构件中增加新的职责,每一个具体装璜类都定义了一些新的行为,能够调用形象装璜类中定义的办法,并能够减少新的职责用以裁减对象的行为

2 典型实现

2.1 步骤

  • 定义形象构件类:能够是抽象类或者接口,申明业务办法
  • 定义具体构件类:继承或实现形象构件,实现具体业务办法
  • 定义形象装璜类:继承或实现形象构件,减少一个形象构件公有成员,通过该成员能够调用装璜之前具体构件的办法
  • 定义具体装璜类:继承形象装璜类,并且减少装璜行为,在装璜之前调用具体构件办法,接着调用装璜办法

2.2 形象构件类

简化只有一个业务办法:

abstract class Component
{abstract void operation();
}

2.3 具体构件类

继承形象构件:

class ConcreteComponent extends Component
{public void operation()
    {System.out.println("具体构件办法");
    }
}

2.4 形象装璜类

class Decorator extends Component
{
    private Component component;

    public Decorator(Component component)
    {this.component = component;}

    public void operation()
    {component.operation();
    }
}

形象装璜类须要蕴含一个形象构件的公有成员,以便能够通过 setter 或构造方法注入不同的具体构件,同时在业务办法中不便调用具体构件未装璜之前的办法。

2.5 具体装璜类

class ConcreteDecorator extends Decorator
{public ConcreteDecorator(Component component)
    {super(component);
    }

    public void operation()
    {super.operation();
        newBehavior();}

    public void newBehavior()
    {System.out.println("装璜办法");
    }
}

继承形象装璜类,在业务办法中首先调用父类(形象装璜类)的办法再调用新的装璜办法。

3 实例

设计一个图形界面构件库,具体构件有窗体,文本框以及列表框,装璜办法包含增加滚动条与增加黑边框,应用装璜模式对系统进行设计。

设计如下:

  • 形象构件类:Component
  • 具体构件类:Window+TextBox+ListBox
  • 形象装璜类:Decorator
  • 具体装璜类:ScrollBarDecorator+BlackBorderDecorator
public class Test
{public static void main(String[] args) {Component component = new Window();
        Component decorator = new ScrollBarDecorator(component);
        decorator.display();}
}

abstract class Component
{abstract void display();
}

class Window extends Component
{public void display()
    {System.out.println("显示窗口");
    }
}

class TextBox extends Component
{public void display()
    {System.out.println("显示文本框");
    }
}

class ListBox extends Component
{public void display()
    {System.out.println("显示列表框");
    }
}

class Decorator extends Component
{
    private Component component;

    public Decorator(Component component)
    {this.component = component;}

    public void display()
    {component.display();
    }
}

class ScrollBarDecorator extends Decorator
{public ScrollBarDecorator(Component component)
    {super(component);
    }

    public void display()
    {addScrollBar();
        super.display();}

    public void addScrollBar()
    {System.out.println("增加滚动条");
    }
}

class BlackBorderDecorator extends Decorator
{public BlackBorderDecorator(Component component)
    {super(component);
    }

    public void display()
    {addBlackBorder();
        super.display();}

    public void addBlackBorder()
    {System.out.println("增加黑边框");
    }
}

输入如下:

外围局部就是客户端的代码:

Component component = new Window();
Component decorator = new ScrollBarDecorator(component);
decorator.display();

创立具体构件后,再创立具体装璜器,把具体构件传入具体装璜器的构造方法中,这样具体装璜器就能在装璜之后(在增加滚动条之后)调用具体构件的办法(调用显示窗口)。

另外,如果向减少新的装璜办法,比方减少了滚动条后,再减少黑边框,只须要将”滚动条装璜器“自身再装璜一次:

Component component = new Window();
Component decorator = new ScrollBarDecorator(component);
decorator = new BlackBorderDecorator(decorator);
decorator.display();

也就是把曾经对具体构件进行装璜之后的具体装璜器,注入到另一个具体装璜器的构造方法再一次装璜。

4 通明装璜与半透明装璜

4.1 通明装璜模式

规范的装璜模式就是通明装璜,比方上述例子。在通明装璜模式中,要求客户端齐全针对形象构件编程,也就是将对象全副申明为形象构件类型,而不是具体构件类型或具体装璜器类型。

通明装璜模式的长处如下:

  • 客户端通明地应用装璜前以及装璜后的对象,毋庸关怀两者区别
  • 能对已装璜过的对象进行屡次装璜

在实现通明装璜模式时,要求具体装璜类的业务办法笼罩形象装璜类的业务办法,须要调用原有具体构件对象的业务办法以及新增装璜办法。

4.2 半透明装璜模式

对于有时用户须要独自调用装璜办法,这时候须要应用具体装璜类型定义装璜后的对象,而具体构件对象还是能够应用形象构件定义,这种装璜模式就叫半透明装璜模式。对于客户端来说:

  • 具体构件类型无需关怀,是通明的
  • 具体装璜类型必须指定,是不通明的

例子如下,批改下面的滚动条具体装璜类:

class ScrollBarDecorator extends Decorator
{public ScrollBarDecorator(Component component)
    {super(component);
    }

    public void display()
    {super.display();
    }

    public void addScrollBar()
    {System.out.println("增加滚动条");
    }
}

其中 addScrollBar 由客户端独自调用:

Component component = new Window();
ScrollBarDecorator decorator = new ScrollBarDecorator(component);
decorator.display();
decorator.addScrollBar();

半透明装璜能够带来更大的灵活性,应用起来更加不便,客户端能够独自调用装璜办法来进行装璜,然而毛病就是不能对同一个对象进行屡次装璜,

5 注意事项

  • 放弃接口雷同:尽量放弃装璜类的接口与被装璜类的接口雷同,这样对客户端而言装璜前 / 后的对象能够统一看待,也就是尽量应用通明装璜模式
  • 缩小具体构件行为:过多的行为不须要放在具体构件类中,通过具体装璜类进行扩大
  • 去除形象构件:如果只有一个具体构件类,那么形象装璜类能够作为该具体构件类的间接子类,也就是说将原来的形象构件用具体构件代替

6 次要长处

  • 动静扩大灵便:对于扩大一个对象的性能,装璜模式比继承更加灵便,不会导致类的个数急剧减少。通过抉择不同的具体装璜类,能够动静扩大对象的行为
  • 屡次装璜:能够对一个对象进行屡次装璜,应用不同的具体装璜类以及这些装璜类的排列组合,能够发明很多不同行为的组合
  • 构件与装璜类独立变动:具体构件类以及具体装璜类能够独立变动,用户能够依据须要减少新的具体构件类或者具体装璜类,毋庸批改原有代码,合乎开闭准则

7 次要毛病

  • 对象较多:应用装璜模式会产生很多小对象,这些对象的区别在于相互连接形式的不同,小对象过多会肯定水平上影响性能
  • 排查繁琐:只管装璜模式比继承更加灵便,但也意味着比继承更加容易出错,排错也很艰难,对于屡次装璜后的对象可能须要逐级排查

8 实用场景

  • 在不影响其余对象的状况下,以动静和通明的形式给单个对象减少职责
  • 在不能采纳继承扩大零碎或者采纳继承不利于对系统扩大和保护时能够应用装璜模式

9 总结

退出移动版