总代理大型网站建设,住房和建设部执业资格注册中心网站,凡科 建设淘宝客网站,大淘客做网站视频定义
装饰模式指的是在不必改变原类文件和使用继承的情况下#xff0c;动态地扩展一个对象的功能。它是通过创建一个包装对象#xff0c;也就是装饰来包裹真实的对象。
模式特点
#xff08;1#xff09; 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对…定义
装饰模式指的是在不必改变原类文件和使用继承的情况下动态地扩展一个对象的功能。它是通过创建一个包装对象也就是装饰来包裹真实的对象。
模式特点
1 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
2 装饰对象包含一个真实对象的引用reference
3 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
4 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中通常是通过继承来实现对给定类的功能扩展。
适用性
以下情况使用Decorator模式
1. 需要扩展一个类的功能或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是可能有大量独立的扩展为支持每一种组合将产生大量的子类使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏或类定义不能用于生成子类。
优点
1. Decorator模式与继承关系的目的都是要扩展对象的功能但是Decorator可以提供比继承更多的灵活性。
2. 通过使用不同的具体装饰类以及这些装饰类的排列组合设计师可以创造出很多不同行为的组合。
缺点
1. 这种比继承更加灵活机动的特性也同时意味着更加多的复杂性。
2. 装饰模式会导致设计中出现许多小类如果过度使用会使程序变得很复杂。
3. 装饰模式是针对抽象组件Component类型编程。但是如果你要针对具体组件编程时就应该重新思考你的应用架构以及装饰者是否合适。当然也可以改变Component接口增加新的公开的行为实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
设计原则
1. 多组合少继承。
利用继承设计子类的行为是在编译时静态决定的而且所有的子类都会继承到相同的行为。然而如果能够利用组合的做法扩展对象的行为就可以在运行时动态地进行扩展。
2. 类应设计的对扩展开放对修改关闭。 在装饰模式中的各个角色有
1抽象构件Component角色给出一个抽象接口以规范准备接收附加责任的对象。
2具体构件Concrete Component角色定义一个将要接收附加责任的类。
3装饰Decorator角色持有一个构件Component对象的实例并实现一个与抽象构件接口一致的接口。
4具体装饰Concrete Decorator角色负责给构件对象添加上附加的责任。
情景假设
变形金刚在变形之前是一辆汽车它可以在陆地上移动。当它变成机器人之后除了能够在陆地上移动之外还可以说话如果需要它还可以变成飞机除了在陆地上移动还可以在天空中飞翔。
情景大概是由汽车拓展成机器人和飞机时该怎么处理 情景分析
关于上面情景的类图具体分析在下面 首先我们很容易想到的是既然要拓展嘛那就先继承汽车拥有汽车的方法然后再在继承类上加上机器人特定的方法那就是机器人啦加上汽车特有的方法那就是汽车类啦。一切都很简单但是论实际上增加一种拓展方式很可能增加非常多的是实现类这将会让系统变得非常的庞大树形的深度越来越深互相耦合程度更加庞大。其次可能还会牵扯到多继承的问题因为有些类可能会继承多个需要拓展的同时使用继承也是破化了类的封装性
所以装饰模式所采用的方法就是利用关联代替继承这样一来降低了继承所导致的耦合度增大同时软件维护上关联关系的松耦合性使得系统更加的容易维护。树形的层数较少在于横向的拓展拓展起来更加方便还能够很好的实现运行时动态拓展。
所以先定义抽象类
//抽象构件类
public abstract class Transform
{public abstract void move();
}具体已有的汽车类
//汽车Car
public final class Car extends Transform{public void Car(){System.out.println(变形金刚是一辆车!);}public void move(){System.out.println(在陆地上移动!);}
}细心的同学发现了我还定义了final声明着这不能继承拓展增加难度这样其实我们就不得不利用关联的方式了。
定义一个装饰类装饰类同样继承抽象类Transform因为装饰类的本质我们不能忘我们只是对原有存在的进行拓展而对于客户端而言应当还是能当作之前的情况继续使用为了实现统一的使用实现同一的抽象类客户端便能够可以无视细节。在这个时候我们可以增加需要被拓展的类作为属性关联起来。
//装饰类Changer
public class Changer extends Transform{private Transform t ;public void add(Transform t){this.t t;}public void move(){t.move();//调用关联类自己的方法}
}接下来就是机器人类和飞机类继承装饰器类即可
public class Robot extends Changer{public Robot(Transform transform){super(transform);System.out.println(变成机器人!);}public void say(){System.out.println(说话);}
}public class AirPlane extends Changer{public AirPlane(Transform transform){super(transform);System.out.println(变成飞机!);}public void fly(){System.out.println(在天空飞翔);}
}接下来是客户端的代码:
public class Client
{public static void main(String args[]){Transform camaro;camaro new Car();camaro.move();Robot bumblebee new Robot(camaro);bumblebee.move();bumblebee.say();}
}可以看到我们这里先定义了一个原先的Car类之后我们再关联起来运用了新的“装饰”的方法。
模式结构及分析 (一) 两种装饰模式 两种装饰模式分别是透明装饰模式和不透明模式。其实这个划分的原因是从客户端的视角来区分的对于客户端来说是透明的还是不透明的。其实这里的理解和我们之前讲的组合模式是一样的我相信如果认真看过我上一篇组合模式的童鞋应该能秒懂和想象得到我接下来讲的是什么
半透明装饰模式 咱们看上面的例子的客户端
public class Client
{public static void main(String args[]){Transform camaro;camaro new Car();camaro.move();Robot bumblebee new Robot(camaro);bumblebee.move();bumblebee.say();}
}我们看到开头两行的代码其实我们一开始设计就已经封装了抽象类Transform但是在实际中并不是统一的定义为什么呢其实是因为我们我们在装饰之后我们新的装饰类子类多了些和之前不同的全新方法而这些方法在抽象类中是没有的以至于只能在具体装饰类中里面去定义实现。
而这对于客户端来说是不透明的 我们原本装饰的目的就是不改变原先的借口进行拓展增强原有的功能但是这里因为装饰后而增加了新的功能以至于我们编写代码的时候不能很好的统一去编写而是要分别定义。但是实际开发中其实半透明还更常见因为增加方法其实是常有的事情。但是有个缺点就是不能实现多重装饰。可以看下面透明模式中客户端代码理解
透明装饰模式 在这模式中针对于客户端操作的统一性就有了透明装饰模式。 上面的例子我们可以修改一下让大家理解其实就是只要在最开始的抽象类中就定义好大家共用的方法即可也即装饰具体类本身也不要去拓展新方法而是稍微的重构或者补充原方法那就可以写成透明装饰模式。
//抽象构件类
public abstract class Transform
{public abstract void move();
}
//汽车Car
public final class Car extends Transform{public void Car(){System.out.println(变形金刚是一辆车!);}public void move(){System.out.println(在陆地上移动!);}
}//装饰类Changer
public class Changer extends Transform{private Transform t ;public void add(Transform t){this.t t;}public void move(){t.move();//调用关联类自己的方法}
}//接下来就是机器人类和飞机类继承装饰器类即可
public class Robot extends Changer{public Robot(Transform transform){super(transform);System.out.println(变成机器人!);}public void move(){System.out.println(连滚带爬的move);}
}public class AirPlane extends Changer{public AirPlane(Transform transform){super(transform);System.out.println(变成飞机!);}public void move(){System.out.println(在天空飞翔的移动);}
}//客户端
public class Client
{public static void main(String args[]){Transform camaro;camaro new Car();camaro.move();Transform bumblebee;bumblebee new Robot(camaro);bumblebee.move();Transform plane;plane new AirPlane(camaro);plane.move();}
}好的可以看到我们抽象构件类定义了统一的方法而在装饰子类中我们也只是增强了原来的方法所以对于客户端我们可以用抽象类去定义然后统一的操作细心的同学肯定发现了我这客户端最后定义的plane用的是我新建装饰器具体类也就是透明模式比半透明模式还好的就是可以实现多重装饰。
(二) 两种组合模式的总结
半透明(Semi-transparent)装饰模式 用具体装饰类型来定义装饰之后的对象而具体构件使用抽象构件类型来定义 对于客户端而言具体构件类型无须关心是透明的但是具体装饰类型必须指定这是不透明的 可以给系统带来更多的灵活性设计相对简单使用起来也非常方便 客户端使用具体装饰类型来定义装饰后的对象因此可以单独调用扩展新增的方法 最大的缺点在于不能实现对同一个对象的多次装饰而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象透明(Transparent)装饰模式 要求客户端完全针对抽象编程装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型而应该全部声明为抽象构件类型 对于客户端而言具体构件对象和具体装饰对象没有任何区别 可以让客户端透明地使用装饰之前的对象和装饰之后的对象无须关心它们的区别 可以对一个已装饰过的对象进行多次装饰得到更为复杂、功能更为强大的对象 无法在客户端单独调用新增拓展方法。只能内嵌使用