装饰者模式(Decorator Pattern)
在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。例如给房子装修,添加家具,给煎饼果子加鸡蛋加香肠
适用场景
- 用于扩展一个类的功能或给一个类添加附加职责。
- 动态的给一个对象添加功能,这些功能可以再动态的撤销。
例如给煎饼果子加鸡蛋加香肠,最简单的方法就是对煎饼果子的方法进行继承,对原有的方法进行增强,但是单纯的继承会存在问题,必须在原有的类上进行继承,无法灵活的加蛋和肠,所以此时可用装饰者模式。
public static void main(String[] args) {Battercake battercake;// 新建煎饼果子对象battercake = new BaseBattercake();// 新建实现类,将基础的煎饼果子通过构造方法带入实现类中,调用煎饼果子的方法battercake = new BattercakeEggDecorator(battercake);// 新建实现类,将加了蛋的煎饼果子通过构造方法带入实现类中,调用他们的方法,+个蛋battercake = new BattercakeEggDecorator(battercake);// .....battercake = new BattercakeSausageDecorator(battercake);System.out.println("购买信息:" + battercake.getMsg() + ",购买价格:" + battercake.getPrice());}
在这里装饰者模式设计还挺有意思,BattercakeDecorator装饰类通过构造方法去调用Battercake的方法,通过使用BattercakeEggDecorator、BattercakeSausageDecorator增强类去加强Battercake的方法(感觉增强方法有点类似套娃)
这里装饰者模式类似静态代理,但两者概念又有所不同,装饰者模式增强方法后本质依旧还是原来的对象,例如煎饼果子加了蛋和肠后,依然还是煎饼果子,而代理模式增强方法后可能完成变成另外一个对象(不是很明白doge)
装饰者模式的优缺点
优点:
- 装饰者是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用。
- 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。
- 装饰者完全遵守开闭原则。
缺点:
- 会出现更多的代码,更多的类,增加程序复杂性。
- 动态装饰时,多层装饰时会更复杂。
观察者模式(Observer Pattern)
定义了对象之间的一对多依赖,让多个观察者对象同时监听一个主体对象,当主体对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新,属于行为型模式。观察者模式有时也叫做发布订阅模式。观察者模式主要用
于在关联行为之间建立一套触发机制的场景。多在消息通知等方面使用,比如微信朋友圈动态通知,邮件通知、广播通知、桌面程序的事件响应。
是学习示例中,有展示JDK自带的观察者(Observer)和被观察者(Observable),也可自行实现监听事件。
// 监听器,它就是观察者的桥梁public class EventListener {/*** JDK 底层的 Lisenter 通常也是这样来设计的*/protected Map<String, Event> events = new HashMap<String, Event>();/*** 事件名称和一个目标对象来触发事件*/public void addListener(String eventType, Object target) {try {this.addListener(eventType, target, target.getClass().getMethod("on" + toUpperFirstCase(eventType), Event.class));} catch (Exception e) {e.printStackTrace();}}public void addListener(String eventType, Object target, Method callback) {// 注册事件events.put(eventType, new Event(target, callback));}/*** 触发,只要有动作就触发*/private void trigger(Event event) {event.setSource(this);event.setTime(System.currentTimeMillis());try {//发起回调if (event.getCallback() != null) {//用反射调用它的回调函数event.getCallback().invoke(event.getTarget(), event);}} catch (Exception e) {e.printStackTrace();}}/*** 逻辑处理的私有方法,首字母大写*/private String toUpperFirstCase(String str) {char[] chars = str.toCharArray();chars[0] -= 32;return String.valueOf(chars);}/*** 判断是否被监听,确认是否触发*/protected void trigger(String trigger) {if (!this.events.containsKey(trigger)) {return;}trigger(this.events.get(trigger).setTrigger(trigger));}}
public class Mouse extends EventListener {public void click() {System.out.println("调用单击方法");this.trigger(MouseEventType.ON_CLICK);}public void doubleClick() {System.out.println("调用双击方法");this.trigger(MouseEventType.ON_DOUBLE_CLICK);}public void up() {System.out.println("调用弹起方法");this.trigger(MouseEventType.ON_UP);}public void down() {System.out.println("调用按下方法");this.trigger(MouseEventType.ON_DOWN);}public void move() {System.out.println("调用移动方法");this.trigger(MouseEventType.ON_MOVE);}public void wheel() {System.out.println("调用滚动方法");this.trigger(MouseEventType.ON_WHEEL);}public void over() {System.out.println("调用悬停方法");this.trigger(MouseEventType.ON_OVER);}public void blur() {System.out.println("调用获焦方法");this.trigger(MouseEventType.ON_BLUR);}public void focus() {System.out.println("调用失焦方法");this.trigger(MouseEventType.ON_FOCUS);}}
//监听器的一种包装, 标准事件源格式的定义@Datapublic class Event {/*** 事件源,事件是由谁发起的保存起来*/private Object source;/*** 事件触发,要通知谁*/private Object target;/*** 事件触发,要做什么动作,回调*/private Method callback;/*** 事件的名称,触发的是什么事件*/private String trigger;/*** 事件触发的时间*/private long time;public Event(Object target, Method callback) {this.target = target;this.callback = callback;}@Overridepublic String toString() {return "Event{" + "\n" + "\tsource=" + source.getClass() + ",\n" + "\ttarget=" + target.getClass() + ",\n" + "\tcallback=" + callback + ",\n" + "\ttrigger='" + trigger + "',\n" + "\ttime=" + time + "'\n" + '}';}public Event setTrigger(String trigger) {this.trigger = trigger;return this;}}
public static void main(String[] args) {MouseEventCallback callback = new MouseEventCallback();// 注册事件Mouse mouse = new Mouse();mouse.addListener(MouseEventType.ON_CLICK, callback);mouse.addListener(MouseEventType.ON_MOVE, callback);mouse.addListener(MouseEventType.ON_WHEEL, callback);mouse.addListener(MouseEventType.ON_OVER, callback);// 触发事件mouse.click();mouse.blur();}
监听执行流程
- 创建触发事件后执行的方法对象
- 注册事件,将执行方法名和方法对象加入监听对象中,此时事件通过Event将触发条件(MouseEventType)、执行对象(MouseEventCallback),执行对象具体某个方法存入在Event中。
- 当事件mouse触发click时,判断出是被监听状态,则执行对应MouseEventType.ON_CLICK 的Event中的方法onClick(Event e)
- 当事件触发blur时,判断出是未被监听状态,则不进行任何操作
观察者模式的优缺点
优点:
- 观察者和被观察者之间建立了一个抽象的耦合。
- 观察者模式支持广播通信。
缺点:
- 观察者之间有过多的细节依赖、提高时间消耗及程序的复杂度。
- 使用要得当,要避免循环调用。
