装饰模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
装饰模式降低了系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类。
优点:扩展性好,不会急剧增加类个数;可以对一个对象进行多次装饰,创造出不同的行为组合;具体构建类和具体装饰类可以独立变化,扩展灵活。
缺点:构建的小对象比较多,有一定程度的性能影响;易出错,排查困难。
要弄清怎么用,还是直接举个例子吧。比如我有一间空房间,我要对它进行装饰,可以加床、桌子、衣柜等等。用代码来实现下。
画一张房间图纸IRoom(抽象角色),有一个show方法用来描述房间内容。
package com.minant.decorator;
/**
* @ClassName IRoom
* @Description TODO 房间接口
* @Author MinAnt
* @Date 2020/5/27
* @Version V1.0
*/
public interface IRoom {
void showRoom();
}
按图纸建一个空房间就是SimpleRoom类(具体角色),将房间过到我的名下就是MyRoom类(装饰角色),此时我就有一个空房间了。在购买几件家具:书桌RoomTable、席梦思RoomBed、衣柜RoomWordRobe(具体装饰角色)。
package com.minant.decorator;
/**
* @ClassName SimpleRoom
* @Description TODO 空房间
* @Author MinAnt
* @Date 2020/5/28
* @Version V1.0
*/
public class SimpleRoom implements IRoom {
@Override
public void showRoom() {
System.out.println("空房间,啥都没有!");
}
}
package com.minant.decorator;
/**
* @ClassName MyRoom
* @Description TODO 我的房间
* @Author MinAnt
* @Date 2020/5/28
* @Version V1.0
*/
public class MyRoom implements IRoom {
private IRoom room;
public MyRoom(IRoom room) {
this.room = room;
}
@Override
public void showRoom() {
room.showRoom();
}
}
package com.minant.decorator;
/**
* @ClassName RoomBed
* @Description TODO 席梦思
* @Author MinAnt
* @Date 2020/5/28
* @Version V1.0
*/
public class RoomBed extends MyRoom {
public RoomBed(IRoom room) {
super(room);
}
private void addBed() {
System.out.println("加了一张席梦思!");
}
@Override
public void showRoom() {
super.showRoom();
this.addBed();
}
}
package com.minant.decorator;
/**
* @ClassName RoomTable
* @Description TODO 书桌
* @Author MinAnt
* @Date 2020/5/28
* @Version V1.0
*/
public class RoomTable extends MyRoom {
public RoomTable(IRoom room) {
super(room);
}
private void addTable() {
System.out.println("加了一张书桌!");
}
@Override
public void showRoom() {
super.showRoom();
this.addTable();
}
}
package com.minant.decorator;
/**
* @ClassName RoomWordRobe
* @Description TODO 衣柜
* @Author MinAnt
* @Date 2020/5/28
* @Version V1.0
*/
public class RoomWordRobe extends MyRoom {
public RoomWordRobe(IRoom room) {
super(room);
}
private void addWordRobe() {
System.out.println("加了一个大衣柜!");
}
@Override
public void showRoom() {
super.showRoom();
this.addWordRobe();
}
}
比较关键的点在于这个MyRoom类,它组合了实现了IRoom的对象属性通过构造方法传入,而具体的装饰类又继承自MyRoom重写了show方法,在show方法中都有super.show();正是这个方法调用使得之前构建的装饰对象会一层层嵌套式的调用到。因此这种装饰模式也会被称为是包装器模式,像给具体角色加外包装一样,一层包一层的。结合测试中看看就更容易理解些了。
package com.minant.decorator;
/**
* @ClassName TestDecorator
* @Description TODO 测试装饰模式
* @Author MinAnt
* @Date 2020/5/28
* @Version V1.0
*/
public class TestDecorator {
public static void main(String[] args) {
// 构建一间我的空房间用于装饰
SimpleRoom room = new SimpleRoom();
MyRoom myRoom = new MyRoom(room);
// 在空房间中加入床
RoomBed bed = new RoomBed(myRoom);
// 在空房间中加入桌
RoomTable table = new RoomTable(bed);
// 在空房间中加入衣柜
RoomWordRobe wordRobe = new RoomWordRobe(table);
// 装饰完毕后的房间
wordRobe.showRoom();
}
}
结果:
看上面的测试代码是不是很像Java中的IO流操作,也是一层包一层的结构,实际上IO流也用到了装饰模式。
装饰模式完。
Stay hungry stay foolish!