装饰器模式
介绍
装饰设计模式允许我们动态地向对象添加功能和行为,而不会影响同一类中其他现有对象的行为。
我们使用继承来扩展类的行为。这在编译时发生,该类的所有实例都会获得扩展行为。
装饰器设计模式允许我们在运行时向对象(而不是类)添加功能,我们可以根据自己的需求和选择将此自定义功能应用于单个对象。
-
装饰器模式允许用户向现有对象添加新功能,而不改变其结构。因此,原始类没有变化。
-
装饰器设计模式是一种结构模式,它为现有类提供包装。
-
装饰器设计模式使用抽象类或具有组合的接口来实现包装器。
-
装饰器设计模式创建装饰器类,它包装原始类,并通过保持类方法的签名不变来提供附加功能。
-
装饰设计模式最常用于应用单一责任原则,因为我们将功能划分为具有独特关注区域的类。
-
装饰设计模式在结构上类似于责任链模式。
实现
让我们看一个例子来更好地理解这个模式。
假设我们有一个Shape
接口
public interface Shape {
void draw();
void resize();
String description();
boolean isHide();
}
现在,我们有两个Shape的具体实现类Circle
和Rectangle
,来定义特定的形状。
下面是Circle
代码示例:
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("画个圈圈");
}
@Override
public void resize() {
System.out.println("调整圆圈的大小");
}
@Override
public String description() {
return "圆形";
}
@Override
public boolean isHide() {
return false;
}
}
下面是Rectangle
代码示例:
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("画个长方形");
}
@Override
public void resize() {
System.out.println("调整长方形大小");
}
@Override
public String description() {
return "长方形";
}
@Override
public boolean isHide() {
return false;
}
}
现在,我们已经可以绘制Circle
和 Rectangle
。但是,我们希望为Shape
提供一些附加功能,如填充颜色、线颜色、线厚度、线样式等。
首先,我们将创建一个实现Shape
的抽象包装器(decorator)类。我将在这个示例中使用ShapeDecorator
。
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape) {
super();
this.decoratedShape = decoratedShape;
}
}
我让ShapeDecorator
类是抽象类,是为了避免直接被实例化,因为这只是一个包装器,没有向Shape
中添加任何功能。此外,我还实现了Shape
,为了给Shape
的实现类(Circle
和Rectanagle
)添加其他功能。
为Shape
的Color
和LineStyle
创建枚举。下面是Color
的枚举:
public enum Color {
/**
* 颜色形状枚举
*/
RED,
GREEN,
BLUE,
YELLOW,
WHITE,
BLACK,
ORANGE,
MAROON
}
下面是LineStyle
的枚举:
public enum LineStyle {
/**
* 线条样式枚举
*/
SOLID,
DASH,
DOT,
DOUBLE_DASH,
DASH_SPACE
}
创建FillColorDecorator
以在形状中添加填充颜色的功能。
public class FillColorDecorator extends ShapeDecorator {
protected Color color;
public FillColorDecorator(Shape decoratedShape, Color color) {
super(decoratedShape);
this.color = color;
}
@Override
public void draw() {
decoratedShape.draw();
System.out.println("填充的颜色是: " + color);
}
/**
* 功能无变化
* 如果愿意,我们可以添加功能。没有限制
* 但需要我们维护Shape API的结构
*/
@Override
public void resize() {
decoratedShape.resize();
}
@Override
public String description() {
return decoratedShape.description() + " filled with " + color + " color.";
}
/**
* 功能无变化
*/
@Override
public boolean isHide() {
return decoratedShape.isHide();
}
}
创建LineColorDecorator
以在形状中添加线条颜色的功能。
public class LineColorDecorator extends ShapeDecorator {
protected Color color;
public LineColorDecorator(Shape decoratedShape, Color color) {
super(decoratedShape);
this.color = color;
}
@Override
public void draw() {
decoratedShape.draw();
System.out.println("线条颜色是: " + color);
}
/**
* 功能无变化
*/
@Override
public void resize() {
decoratedShape.resize();
}
@Override
public String description() {
return decoratedShape.description() + " drawn with " + color + " color.";
}
/**
* 功能无变化
*/
@Override
public boolean isHide() {
return decoratedShape.isHide();
}
}
创建LineThicknessDecorator
以在形状中添加自定义线宽的功能。
public class LineThinknessDecorator extends ShapeDecorator {
protected double thickness;
public LineThinknessDecorator(Shape decoratedShape, double thickness) {
super(decoratedShape);
this.thickness = thickness;
}
@Override
public void draw() {
decoratedShape.draw();
System.out.println("线条宽度是: " + thickness);
}
/**
* 功能无变化
*/
@Override
public void resize() {
decoratedShape.resize();
}
@Override
public String description() {
return decoratedShape.description() + " drawn with line thickness " + thickness + ".";
}
/**
* 功能无变化
*/
@Override
public boolean isHide() {
return decoratedShape.isHide();
}
}
创建LineStyleDecorator
以在形状中添加自定义线样式的功能
public class LineStyleDecorator extends ShapeDecorator {
protected LineStyle style;
public LineStyleDecorator(Shape decoratedShape, LineStyle style) {
super(decoratedShape);
this.style = style;
}
@Override
public void draw() {
decoratedShape.draw();
System.out.println("线条样式是: " + style);
}
/**
* 功能无变化
*/
@Override
public void resize() {
decoratedShape.resize();
}
@Override
public String description() {
return decoratedShape.description() + " drawn with " + style + " lines.";
}
/**
* 功能无变化
*/
@Override
public boolean isHide() {
return decoratedShape.isHide();
}
}
创建一个Main
程序来执行和测试装饰器代码。
public class Main {
public static void main(String[] args) {
Shape rectangle = new Rectangle();
Shape circle = new Circle();
System.out.println("开始绘制图形...");
rectangle.draw();
circle.draw();
System.out.println();
System.out.println("画一个红色、蓝色虚线、厚度为2的圆型 ...");
Shape circle1 = new FillColorDecorator(new LineColorDecorator(new LineStyleDecorator(
new LineThinknessDecorator(new Circle(), 2.0d), LineStyle.DASH), Color.BLUE), Color.RED);
circle1.draw();
System.out.println();
//装饰器的顺序在这里也不太重要,因为它们都是独特的功能。
//我们还可以在单独的语句中嵌套功能。
System.out.println("在单独的语句中创建具有类似功能的对象。");
Circle c = new Circle();
LineThinknessDecorator lt = new LineThinknessDecorator(c, 2.0d);
LineStyleDecorator ls = new LineStyleDecorator(lt, LineStyle.DASH);
LineColorDecorator lc = new LineColorDecorator(ls, Color.BLUE);
FillColorDecorator fc = new FillColorDecorator(lc, Color.RED);
Shape circle3 = fc;
circle3.draw();
System.out.println();
System.out.println("画一个绿色、黑色线条装饰的圆型...");
Shape circle2 = new FillColorDecorator(new LineColorDecorator(new Circle(), Color.BLACK), Color.GREEN);
circle2.draw();
System.out.println();
System.out.println("画一个黄色、红色双划线装饰的矩形...");
Shape rectangle1 = new FillColorDecorator(new LineColorDecorator(new Rectangle(), Color.RED), Color.YELLOW);
rectangle1.draw();
System.out.println();
}
}
程序输出结果:
开始绘制图形...
画个长方形
画个圈圈
画一个红色、蓝色虚线、厚度为2的圆型 ...
画个圈圈
线条宽度是: 2.0
线条样式是: DASH
线条颜色是: BLUE
填充的颜色是: RED
在单独的语句中创建具有类似功能的对象。
画个圈圈
线条宽度是: 2.0
线条样式是: DASH
线条颜色是: BLUE
填充的颜色是: RED
画一个绿色、黑色线条装饰的圆型...
画个圈圈
线条颜色是: BLACK
填充的颜色是: GREEN
画一个黄色、红色双划线装饰的矩形...
画个长方形
线条颜色是: RED
填充的颜色是: YELLOW
Process finished with exit code 0
正如我们所看到的,我们没有更改核心类:Shape
、Circle
和Rectangle
。而是通过创建包装器和装饰器类,我们添加并定制了Shape
、Circle
和Rectangle
的行为。
总结
优点
装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点
多层装饰比较复杂
使用场景
- 扩展一个类的功能。
- 动态增加功能,动态撤销。
经典例子
评论区