Java教程

百万架构师第七课:设计模式:装饰器模式及观察者模式

本文主要是介绍百万架构师第七课:设计模式:装饰器模式及观察者模式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

回顾

适配器模式使用了继承的方法,达到了兼容的目的,或者使用注入的办法也能够达到兼容的目的。适配器模式就是兼容

装饰器模式

  • 为了某个实现类在不修改原始类的基础上进行动态的覆盖或者增加方法。
  • 该实现保持跟原有类的继承关系
  • 采用装饰模式
  • 装饰器模式实际上是一种非常特殊的适配器模式

装饰器模式和适配器模式对比

装饰器模式 适配器模式
是一种非常特别的适配器模式 可以不保留层级关系
装饰者和被装饰者都要实现同一个接口
主要目是为了:扩展,依旧保留 OOP 关系
适配者和被适配者没有必然的层级关系
通常采用代理或者继承的形式进行包装
满足 is - a 的关系 满足 has - a 的关系
注重覆盖、扩展 注重兼容、转换

Spring中 装饰器模式的类:

  • Decorator
  • wrapper

装饰器代码:

Member.class
@Data
public class Member {
    private String userName;
    private String password;
    private String mid;
    private String info;
}
ResultMsg.class
@Data
public class ResultMsg {
    private String code;
    private String msg;
    private Object data;

    public ResultMsg(String code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
}
SigninService.class
@Deprecated // 过时
public interface SigninService {

    ResultMsg regist(String userName, String password);


    ResultMsg login(String userName, String password);
}
SigninServiceImpl.class
public class SigninServiceImpl implements SigninService {
    /***
     * 注册方法
     * @param userName
     * @param password
     * @return
     */
    public ResultMsg regist(String userName, String password) {
        return new ResultMsg("200", "注册成功", new Member());
    }

    /***
     * 登录方法
     * @param userName
     * @param password
     * @return
     */
    public ResultMsg login(String userName, String password) {
        return null;
    }
}
SigninForThirdService.class
public interface SigninForThirdService extends SigninService {
    public ResultMsg loginForQQ(String openId);

    public ResultMsg logForWeChat(String openId);

    public ResultMsg loginForToken(String token);

    public ResultMsg loginForTelephone(String telephone, String code);

    public ResultMsg loginForRegist(String userName, String password);
}
SigninForThirdServiceImpl.class
public class SigninForThirdServiceImpl implements SigninForThirdService {

    private SigninService signinService;

    public SigninForThirdServiceImpl(SigninService signinService) {
        this.signinService = signinService;
    }

    public ResultMsg regist(String userName, String password) {
        return signinService.regist(userName, password);
    }

    public ResultMsg login(String userName, String password) {
        return signinService.login(userName, password);
    }

    public ResultMsg loginForQQ(String openId) {
        // 1. openId 是全局唯一的,我们可以把它当作一个用户名(加长)
        // 2. 密码默认为 QQ_EMPTY
        // 3. 注册(在原有的系统里边创建一个用户)
        // 4. 调用原来的登陆方法
        return this.loginForRegist(openId, null);
    }

    public ResultMsg logForWeChat(String openId) {
        return null;
    }

    public ResultMsg loginForToken(String token) {
        // 通过 token 拿到用户信息,然后再重新登录一次
        return null;
    }

    public ResultMsg loginForTelephone(String telephone, String code) {
        //
        return null;
    }

    public ResultMsg loginForRegist(String userName, String password) {
        this.regist(userName, password);
        return this.login(userName, password);
    }
}
SignninTest.class
public class SignninTest {
    public static void main(String[] args) {
        // 原来的功能依旧对外开放,依旧保留
        // 新的功能同样地也可以使用
        SigninForThirdService signinForThirdService = new SigninForThirdServiceImpl(new SigninServiceImpl());
    }
}
DecotratorTest.class
public class DecotratorTest {
    public static void main(String[] args) {
        // 为了某个实现类在不修改原始类的基础上进行动态的覆盖或者增加方法。
        // 该实现保持跟原有类的继承关系
        // 采用装饰模式
        // 装饰器模式实际上是一种非常特殊的适配器模式

        // 虽然 DAtaInputStream 功能更强大
        // DataInputStream 同样去实现 InputStrem
        InputStream in = null;
        DataInputStream fis = new DataInputStream(in);
    }
}
assets/装饰器模式中类图.png

装饰器模式中类图

观察者模式

发布者(Publish)和订阅者(Subscribe)

订阅者一直在观察发布者

订阅方是观察者模式,目的:解耦。

观察模式通常会跟代理模式混合使用。

监听器都是用的观察者模式

assets/观察者模式Lily照片.png

观察者模式Lily照片

Event.class
public class Event {

    // 事件源 ( set 方法, 只有同一个包下可以调用)
    private Object source;
    // 通知目标
    private Object target;
    // 回调
    private Method callback;
    // 触发 ( set 方法, 只有同一个包下可以调用)
    private String trigger;
    // 时间
    private Date time;

    public Event(Object target, Method callback) {
        this.target = target;
        this.callback = callback;
    }

    public Object getSource() {
        return source;
    }

    void setSource(Object source) {
        this.source = source;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public Method getCallback() {
        return callback;
    }

    public void setCallback(Method callback) {
        this.callback = callback;
    }

    public String getTrigger() {
        return trigger;
    }

    Event setTrigger(String trigger) {
        this.trigger = trigger;
        return this;
    }

    public Date getTime() {
        return time;
    }

    Event setTime(Date time) {
        this.time = time;
        return this;
    }

    @Override
    public String toString() {
        return "Event{" + "\n" +
                "\tsource=" + source + ",\n" +
                "\ttarget=" + target + ",\n" +
                "\tcallback=" + callback + ",\n" +
                "\ttrigger='" + trigger + '\'' + ",\n" +
                "\ttime=" + time + ",\n" +
                '}';
    }
}
EventListener.class
/**
 * 事件的注册和监听
 * <br>Darian
 **/
public class EventListener {

    protected Map<Enum, Event> events = new HashMap<Enum, Event>();

    public void addListener(Enum eventType, Object target, Method callback){
        // 注册时间
        // 用反射调用这个方法
        events.put(eventType, new Event(target, callback));
    }

    private void trigger(Event e){
        e.setSource(this);
        e.setTime(new Date());

        try {
            e.getCallback().invoke(e.getTarget(),e);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    protected void trigger(Enum call){
        if( !this.events.containsKey(call)){
            return ;
        }
        trigger(this.events.get(call).setTrigger(call.toString()));
    }
}
Observer.class
public class Observer {
    public void advice(Event e) {
        System.out.println("=======触发事件,打印日志=========\n" + e);

        /**
         * input
         * input.addListener("click", function(){
         * })
         **/
    }
}
Subject.class
public class Subject extends EventListener {

    // 通常说的话,采用动态代理实现监控,避免代码侵入

    public void add(){
        System.out.println("调用一个添加的方法");
        trigger(SubjectEventType.ON_ADD);
    }

    public void remore(){
        System.out.println("调用删除的方法");
        trigger(SubjectEventType.ON_REMOVE);
    }
}
SubjectEventType.class
public enum  SubjectEventType {
    ON_ADD,
    ON_REMOVE,
    ON_EDIT,
    ON_QUERY
}
ObserverTest.class
public class ObserverTest {
    public static void main(String[] args) {
        try {
            // 观察者
            Observer observer = new Observer();
            Method advice = observer.getClass().getMethod("advice", new Class<?>[]{Event.class});
            // 这里写 Lily
            Subject subject = new Subject();
            subject.addListener(SubjectEventType.ON_ADD, observer, advice);
            subject.addListener(SubjectEventType.ON_REMOVE, observer,advice);

            subject.add();
            subject.remore();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
assets/观察者模式EventListener类图.png

观察者模式EventListener类图

Mourse 鼠标的点击事件

Mouse.class
/**
 * 如果有过 Swing 开发经验的话,就会有一种似曾相识的感觉
 * <br>Darian
 **/
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 wheel() {
        System.out.println("鼠标滚动");
        this.trigger(MouseEventType.ON_WHEEL);
    }

    public void move() {
        System.out.println("鼠标移动");
        this.trigger(MouseEventType.ON_MOVE);
    }

    public void over() {
        System.out.println("鼠标悬停");
        this.trigger(MouseEventType.ON_OVER);
    }
}

MouseEventCallBack.class
/**
 * 观察者
 *
 * 回调响应的逻辑,由自己实现
 * <br>Darian
 **/
public class MouseEventCallBack {
    public void onClick(Event e) {
        System.out.println(">>>>>>>>>>>这是鼠标单击以后要执行的逻辑:开始");
        System.out.println("===========触发了鼠标的单击事件============\n" + e);
        System.out.println(">>>>>>>>>>>这是鼠标单击以后要执行的逻辑:结束");
    }

    public void onDoubleClick(Event e) {
        System.out.println("===========触发了鼠标的双击事件============\n" + e);
    }

    public void onUp(Event e) {
        System.out.println("===========触发了鼠标的弹起事件============\n" + e);
    }

    public void onDown(Event e) {
        System.out.println("===========触发了鼠标的按下事件============\n" + e);
    }

    public void onWheel(Event e) {
        System.out.println("===========触发了鼠标的滚动事件============\n" + e);
    }

    public void onMove(Event e) {
        System.out.println("===========触发了鼠标的移动事件============\n" + e);
    }

    public void onOver(Event e) {
        System.out.println("===========触发了鼠标的悬停事件============\n" + e);
    }
}
MouseEventType.class
public enum MouseEventType {
    ON_CLICK,
    ON_DOUBLE_CLICK,
    ON_UP,
    ON_DOWN,
    ON_WHEEL,
    ON_MOVE,
    ON_OVER;
}
MouseTest.class
public class MouseTest {
    public static void main(String[] args) {
        /***
         *      var input = document.getElementById("username");
         *      input.addListener("click", function(){
         *           alert("鼠标点击了这个文本框 ")
         *      });
         *
         * 给一个回调的逻辑
         */

        // 观察者和被观察者之间没有必然的联系
        // 注册的时候,才产生联系

        // 解耦

        try {
            MouseEventCallBack callBack = new MouseEventCallBack();
            Method onClick = MouseEventCallBack.class.getMethod("onClick", Event.class);

            // 人为地调用鼠标的单击事件
            Mouse mouse = new Mouse();
            mouse.addListener(MouseEventType.ON_CLICK, callBack, onClick);

            mouse.click();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
控制台输出
Connected to the target VM, address: '127.0.0.1:7419', transport: 'socket'
调用一个添加的方法
Disconnected from the target VM, address: '127.0.0.1:7419', transport: 'socket'
=======触发事件,打印日志=========
Event{
	source=com.darian.pattern.observer.subject.Subject@3419866c,
	target=com.darian.pattern.observer.subject.Observer@63e31ee,
	callback=public void com.darian.pattern.observer.subject.Observer.advice(com.darian.pattern.observer.core.Event),
	trigger='ON_ADD',
	time=Sat Oct 06 03:01:46 CST 2018,
}
调用删除的方法
=======触发事件,打印日志=========
Event{
	source=com.darian.pattern.observer.subject.Subject@3419866c,
	target=com.darian.pattern.observer.subject.Observer@63e31ee,
	callback=public void com.darian.pattern.observer.subject.Observer.advice(com.darian.pattern.observer.core.Event),
	trigger='ON_REMOVE',
	time=Sat Oct 06 03:01:46 CST 2018,
}
assets/观察者模式Mouse类图.png

观察者模式Mouse类图
来源于: https://javaguide.net

微信公众号:不止极客

这篇关于百万架构师第七课:设计模式:装饰器模式及观察者模式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!