装饰模式简介
- 装饰模式(Decorator Pattern)是一种结构型设计模式,它让你能够向对象动态地添加新功能。这种模式特别适用于你想要扩展一个类的功能,或者给某个对象添加附加职责的时候,而且这一切都在不改变其他对象的情况下完成。装饰模式经常作为替代继承机制的选择,因为它提供了比继承更大的灵活性。
业务场景
- 动态地给对象添加职责:如果需要在运行时决定是否给对象添加额外的行为,那么装饰模式非常适合这种情况。比如,根据用户的权限级别动态地赋予系统中的用户不同的访问权限。
- 需要灵活地组合对象的行为:装饰模式允许你通过组合不同的装饰器来给对象添加多种行为。这使得你可以根据需要构造出各种各样的行为组合。
- 当不能使用子类时:有时候可能不允许修改现有的类(例如第三方库),或者修改类的成本很高,这时可以通过装饰模式来达到类似的效果。
模板代码
取自《大话设计模式》,基于java实现的装饰模式demo.
abstract class Component {
public abstract void operation();
}
public class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("具体对象的实际操作");
}
}
//具体装饰类A
public class ConcreteDecoratorA extends Decorator {
private String addedState;
@Override
public void operation() {
super.operation();
this.addedState = "具体装饰对象A独有状态";
System.out.println(this.addedState);
}
}
//具体装饰类B
public class ConcreteDecoratorB extends Decorator {
private void addedState() {
System.out.println("具体装饰对象B独有方法");
}
@Override
public void operation() {
super.operation();
this.addedState();
}
}
public class Decorator extends Component {
protected Component component;
//装饰一个component
public void setComponent(Component component) {
this.component = component;
}
//重写operation,实际调用component的op方法
@Override
public void operation() {
if (component != null) {
component.operation();
}
}
}
//主启动类,客户端
public class App {
public static void main(String[] args) {
ConcreteComponent c=new ConcreteComponent();
ConcreteDecoratorA a=new ConcreteDecoratorA();
ConcreteDecoratorB b=new ConcreteDecoratorB();
//a用来装饰c
a.setComponent(c);
//b装饰a
b.setComponent(a);
//执行b的operation,发现三者operation全部执行
b.operation();
}
}
业务场景应用
-
业务场景为系统与其他模块建立连接,通信协议有很多种。在这种情况下,系统需要对目标模块发送报文,报文段一般由多种部分组成,每个通信协议也不一样。
-
因此在系统中,通常实际的功能由报文段的Data部分承担,这也是报文段的有效载荷,即应用程序的实际数据。而报文的其他内容,如报文头、报文长度、报文尾等需要根据不同协议去动态生成。此时可以通过装饰模式,设计出不同的handler,对不同协议的报文添加不同的内容。
以下为基于该业务场景设计的demo代码
//messageHandler,定义了所有报文段处理类的规范,具有handle方法,处理报文段
public interface MessageHandler {
String handle(String msg);
}
//所有具体concreteHandler的父类,具有装饰方法和handle方法
public class BaseHandler implements MessageHandler {
MessageHandler messageHandler;
//装饰对象
public void decorate(MessageHandler messageHandler) {
this.messageHandler = messageHandler;
}
@Override
public String handle(String msg) {
//调用具体messageHandler的handle方法
if (messageHandler != null) {
return messageHandler.handle(msg);
}
return msg;
}
}
以下为concreteHandler的实现
//该handler用于统计报文长度(不包含报文头和报文尾)
public class MsgLengthHandler extends BaseHandler {
@Override
public String handle(String msg) {
msg = "Context Length:" + msg.length() + "::" + msg;
return super.handle(msg);
}
}
//该handler用于添加tcp报文头,可根据需要添加不同报文头的handler
public class TcpHeadHandler extends BaseHandler {
@Override
public String handle(String msg) {
msg = "Tcp Head::" + msg;
return super.handle(msg);
}
}
//该handler用于添加tcp报文尾
public class TcpTailHandler extends BaseHandler {
@Override
public String handle(String msg) {
msg = msg + "::Tcp Tail";
return super.handle(msg);
}
}
最后是客户端方法,此处需要注意装饰顺序,否则会出现报文长度计算错误的情况.
public class App {
public static MessageHandler handler;
public static void main(String[] args) {
String msg = "this is a message context";
MsgLengthHandler msgLengthHandler = new MsgLengthHandler();
TcpHeadHandler tcpHeadHandler = new TcpHeadHandler();
TcpTailHandler tcpTailHandler = new TcpTailHandler();
//先计算报文长度,再加报文头,最后加报文尾
tcpHeadHandler.decorate(tcpTailHandler);
msgLengthHandler.decorate(tcpHeadHandler);
handler = msgLengthHandler;
msg = handler.handle(msg);
System.out.println(msg);
}
}