装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。比如,一张照片,不改变照片本身,增加一个相框。
装饰模式是一种用于替代继承的技术,无须定义子类即可给对象动态增加职责,使用对象之间的关联关系来代替继承关系,在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类方法,还可以增加新的方法,以扩充原有的类功能。
装饰模式:动态地给对象增加一些额外的职责。
就增加对象功能来说,装饰模式比生成子类实现更为灵活,装饰模式是一种对象结构型模式。
简化只有一个业务方法:
abstract class Component
{
abstract void operation();
}
继承抽象构件:
class ConcreteComponent extends Component
{
public void operation()
{
System.out.println("具体构件方法");
}
}
class Decorator extends Component
{
private Component component;
public Decorator(Component component)
{
this.component = component;
}
public void operation()
{
component.operation();
}
}
抽象装饰类需要包含一个抽象构件的私有成员,以便可以通过setter或构造方法注入不同的具体构件,同时在业务方法中方便调用具体构件未装饰之前的方法。
class ConcreteDecorator extends Decorator
{
public ConcreteDecorator(Component component)
{
super(component);
}
public void operation()
{
super.operation();
newBehavior();
}
public void newBehavior()
{
System.out.println("装饰方法");
}
}
继承抽象装饰类,在业务方法中首先调用父类(抽象装饰类)的方法再调用新的装饰方法。
public static void main(String[] args)
{
Component component = new ConcreteComponent();
Component decorator = new ConcreteDecorator(component);
decorator.operation();
}
客户端针对抽象构件编程即可,无需指定具体装饰类或者具体构件类的类型,使用装饰器时,通过构造方法注入具体构件,直接调用业务方法即可。
设计一个图形界面构件库,具体构件有窗体,文本框以及列表框,装饰方法包括添加滚动条与添加黑边框,使用装饰模式对系统进行设计。
设计如下:
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();
也就是把已经对具体构件进行装饰之后的具体装饰器,注入到另一个具体装饰器的构造方法再一次装饰。
标准的装饰模式就是透明装饰,比如上述例子。在透明装饰模式中,要求客户端完全针对抽象构件编程,也就是将对象全部声明为抽象构件类型,而不是具体构件类型或具体装饰器类型。
透明装饰模式的优点如下:
在实现透明装饰模式时,要求具体装饰类的业务方法覆盖抽象装饰类的业务方法,需要调用原有具体构件对象的业务方法以及新增装饰方法。
对于有时用户需要单独调用装饰方法,这时候需要使用具体装饰类型定义装饰后的对象,而具体构件对象还是可以使用抽象构件定义,这种装饰模式就叫半透明装饰模式。对于客户端来说:
例子如下,修改上面的滚动条具体装饰类:
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();
半透明装饰可以带来更大的灵活性,使用起来更加方便,客户端可以单独调用装饰方法来进行装饰,但是缺点就是不能对同一个对象进行多次装饰。
如果觉得文章好看,欢迎点赞。
同时欢迎关注微信公众号:氷泠之路。