装饰者模式(Decorator Pattern)是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能)
属于结构型模式
适用场景: 1 用于扩展一个类的功能或给一个类添加附加职责0
2 动态的给一个对象添加功能,这些功能可以再动态的撤销
装饰者模式 | 适配器模式 | |
形式 | 是一种非常特别的适配器模式 | 没有层级关系,装饰器模式有层级关系 |
定义 | 装饰者和被装饰者都实现同一个接口,主要目的是为了扩展之后依旧保留OOP关系 | 适配器和被适配者没有必然的联系,通常是采用继承或代理的形式进行包装 |
关系 | 满足is-a的关系 | 满足has-a的关系 |
功能 | 注重覆盖、扩展 | 注重兼容、转换 |
设计 | 前置考虑 | 后置考虑 |
public abstract class Battercake { protected abstract String getMsg(); protected abstract int getPrice(); }
public class BaseBattercake extends Battercake { @Override protected String getMsg(){ return "煎饼"; } @Override public int getPrice(){ return 5; } }
public abstract class BattercakeDecorator extends Battercake { /** * 静态代理,委派 */ private Battercake battercake; public BattercakeDecorator(Battercake battercake) { this.battercake = battercake; } protected abstract void doSomething(); @Override protected String getMsg() { return this.battercake.getMsg(); } @Override protected int getPrice() { return this.battercake.getPrice(); } }
public class EggDecorator extends BattercakeDecorator { public EggDecorator(Battercake battercake) { super(battercake); } @Override protected void doSomething() { } @Override protected String getMsg() { return super.getMsg() + "+1个鸡蛋"; } @Override protected int getPrice() { return super.getPrice() + 1; } }
public class SausageDecorator extends BattercakeDecorator { public SausageDecorator(Battercake battercake) { super(battercake); } @Override protected void doSomething() { } @Override protected String getMsg() { return super.getMsg() + "+1根香肠"; } @Override protected int getPrice() { return super.getPrice() + 2; } }
public static void main(String[] args) { Battercake battercake; //路边摊买一个煎饼 battercake = new BaseBattercake(); //煎饼有点小,想再加一个鸡蛋 battercake = new EggDecorator(battercake); //很饿,再加根香肠 battercake = new SausageDecorator(battercake); //跟静态代理最大区别就是职责不同 //静态代理不一定要满足is-a的关系 //静态代理会做功能增强,同一个职责变得不一样 //装饰器更多考虑是扩展 System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice()); }
优点: 1 装饰者是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用
2 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
3 装饰者完全遵守开闭原则
缺点:1 会出现更多的代码,更多的类,增加程序复杂性
2 动态装饰时,多层装饰时会更复杂
public class Member { private String username; private String password; private String mid; private String info; }
public class ResultMsg { private int code; private String msg; private Object data; public ResultMsg(int code, String msg, Object data) { this.code = code; this.msg = msg; this.data = data; } }
public interface ISigninService { ResultMsg regist(String username, String password); /** * 登录的方法 * @param username * @param password * @return */ ResultMsg login(String username, String password); }
public interface ISiginForThirdService extends ISigninService { /** * QQ登录 * @param id * @return */ ResultMsg loginForQQ(String id); /** * 微信登录 * @param id * @return */ ResultMsg loginForWechat(String id); /** * 记住登录状态后自动登录 * @param token * @return */ ResultMsg loginForToken(String token); /** * 手机号登录 * @param telphone * @param code * @return */ ResultMsg loginForTelphone(String telphone, String code); /** * 注册后自动登录 * @param username * @param passport * @return */ ResultMsg loginForRegist(String username, String passport); }
public class SiginForThirdService implements ISiginForThirdService { private ISigninService signinService; public SiginForThirdService(ISigninService signinService) { this.signinService = signinService; } @Override public ResultMsg regist(String username, String password) { return signinService.regist(username,password); } @Override public ResultMsg login(String username, String password) { return signinService.login(username,password); } @Override public ResultMsg loginForQQ(String id) { return null; } @Override public ResultMsg loginForWechat(String id) { return null; } @Override public ResultMsg loginForToken(String token) { return null; } @Override public ResultMsg loginForTelphone(String telphone, String code) { return null; } @Override public ResultMsg loginForRegist(String username, String passport) { return null; } }
public static void main(String[] args) { //满足一个is-a ISiginForThirdService siginForThirdService = new SiginForThirdService(new SigninService()); siginForThirdService.loginForQQ("Decorator"); }
源码中运用装饰器模式:
HttpHeadResponseDecorator继承的父类 ServerHttpResponseDecorator