「补课」进行时:设计模式(10)——小明起床记了解装饰模式
1. 前文汇总
2. 小明起床记
小明每天早晨都是起床困难大户,大冬天的太冷了,温暖的被窝紧紧的拉住小明,阻止小明每天早晨的起床。
闹钟响了一遍又一遍,如果再不起床就要迟到了,迟到了就要扣钱,扣了钱就要喝西北风了。
每天早晨督促小明起床的根本不是闹钟,而是贫穷。
起床第一件事儿是穿衣服,先传衣服,再传裤子,然后穿鞋子,最后穿上一件外套,出门上班。
首先,定义一个抽象的小明,小明是个人,所以定义一个人:
public abstract class Person {
abstract void dress();
}
每个人早晨起床都要穿衣服,这里定义一个穿衣服的方法。
具体的小明上线:
public class Man extends Person {
@Override
void dress() {
System.out.println("先穿衣服");
}
}
接下来我们要定义一个抽象的装饰器了,小明要穿的是衣服,我们将衣服抽象成一个类:
public abstract class Clothes extends Person {
private Person person;
public Clothes(Person person) {
this.person = person;
}
@Override
void dress() {
this.person.dress();
}
}
接下来是具体的衣服:
public class Trousers extends Clothes {
public Trousers(Person person) {
super(person);
}
@Override
void dress() {
super.dress();
this.dressTrousers();
}
private void dressTrousers() {
System.out.println("穿上裤子啦!!!");
}
}
public class Shoes extends Clothes {
public Shoes(Person person) {
super(person);
}
@Override
void dress() {
super.dress();
this.dressShoes();
}
private void dressShoes() {
System.out.println("穿上鞋子啦!!!");
}
}
public class Coat extends Clothes {
public Coat(Person person) {
super(person);
}
@Override
void dress() {
super.dress();
this.dressCoat();
}
private void dressCoat() {
System.out.println("穿上外套啦!!!");
}
}
最后是一个测试类:
public class Test1 {
public static void main(String[] args) {
Person person = new Man();
person.dress();
System.out.println("--------------");
System.out.println("增加裤子适配器");
person = new Trousers(person);
person.dress();
System.out.println("--------------");
System.out.println("增加鞋子适配器");
person = new Shoes(person);
person.dress();
System.out.println("--------------");
System.out.println("增加外套适配器");
person = new Coat(person);
person.dress();
}
}
测试结果如下:
先穿衣服
--------------
增加裤子适配器
先穿衣服
穿上裤子啦!!!
--------------
增加鞋子适配器
先穿衣服
穿上裤子啦!!!
穿上鞋子啦!!!
--------------
增加外套适配器
先穿衣服
穿上裤子啦!!!
穿上鞋子啦!!!
穿上外套啦!!!
上面这么写有点麻烦,我们可以稍微缩减一下测试类,使用装饰器嵌套,一次性直接把所有的衣服都穿好:
public class Test2 {
public static void main(String[] args) {
Person person = new Coat(new Shoes(new Trousers(new Man())));
person.dress();
}
}
3. 装饰器模式
3.1 定义
装饰模式(Decorator Pattern)是一种比较常见的模式,其定义如下:
Attachadditional responsibilities to an object dynamically keeping the sameinterface.Decorators provide a flexible alternative to subclassing forextending functionality.(动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。)
- Component: 抽象构件,是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象。
- ConcreteComponent: 具体构件,是最核心、最原始、最基本的接口或抽象类的实现。
- Decorator: 通用的装饰 ConcreteComponent 的装饰器,其内部必然有一个属性指向 Component 抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个 Component 抽象组件,这是强制的通用行为(当然,如果系统中装饰逻辑单一,并不需要实现许多装饰器,那么我们可以直接省略该类,而直接实现一个 具体装饰器(ConcreteDecorator) 即可)。
- ConcreteDecorator: Decorator 的具体实现类,理论上,每个 ConcreteDecorator 都扩展了 Component 对象的一种功能。
通用代码:
public abstract class Component {
abstract void operate();
}
public class ConcreteComponent extends Component {
@Override
void operate() {
System.out.println("do Something");
}
}
public abstract class Decorator extends Component {
private Component component = null;
// 通过构造函数传递被修饰者
public Decorator(Component component) {
this.component = component;
}
// 委托给被修饰者执行
@Override
void operate() {
this.component.operate();
}
}
public class ConcreteDecorator1 extends Decorator {
// 定义被修饰者
public ConcreteDecorator1(Component component) {
super(component);
}
private void method1() {
System.out.println("method1 修饰");
}
@Override
void operate() {
this.method1();
super.operate();
}
}
public class ConcreteDecorator2 extends Decorator {
public ConcreteDecorator2(Component component) {
super(component);
}
private void method2() {
System.out.println("method2 修饰");
}
@Override
void operate() {
super.operate();
this.method2();
}
}
public class Test {
public static void main(String[] args) {
Component component = new ConcreteComponent();
// 第一次修饰
component = new ConcreteDecorator1(component);
// 第二次修饰
component = new ConcreteDecorator2(component);
// 修饰后运行
component.operate();
}
}
3.2 优点
装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说, Component 类无须知道 Decorator 类, Decorator 类是从外部来扩展 Component 类的功能,而 Decorator 也不用知道具体的构件。
3.3 缺点
对于装饰模式记住一点就足够了:多层的装饰是比较复杂的。为什么会复杂呢?想想看,就像剥洋葱一样,至于剥到了最后才发现是最里层的装饰出现了问题,想象一下工作量吧,因此,尽量减少装饰类的数量,以便降低系统的复杂度。
3.3 使用场景
- 需要扩展一个类的功能,或给一个类增加附加功能。
- 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
- 需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式。
作者:极客挖掘机
定期发表作者的思考:技术、产品、运营、自我提升等。
本文版权归作者极客挖掘机和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果您觉得作者的文章对您有帮助,就来作者个人小站逛逛吧:极客挖掘机