2、9装饰模式
定义
装饰模式,动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活,或者说是装饰者提供了比继承更有弹性的替代方案。。
通用类图-1
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
如果只有一个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
同样的道理,如果只有一个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流类图
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