了解Spring中常见的设计模式-------------------观察者模式

观察者模式(Observer Pattern)

定义了对象之间的一对多依赖,让多个观察者对象同时监听一个主体对象,当主体对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。

属于行为型模式

观察者模式有时也叫做发布订阅模式。

适用的场景:

1、用于在关联行为之间建立一套触发机制的场景;

2、一个对象必须通知其他的对象,而并不知道这些对象是谁;

3、需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象,可以使用观察者模式创建一种链式触发机制;

优点:观察者和被观察者之间建立了一个抽象的耦合;观察者模式支持广播通信;

缺点:

1、如果观察者对象有很多的直接或者间接的观察者的话,将所有的观察者都通知到会花很多的时间;

2、如果观察者与被观察者之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;

3、观察者之间有过多的细节依赖,提高时间消耗及程序的复杂度;

注意事项:

1、JAVA中已经有了对观察者模式的支持类

2、避免循环引用

3、如果顺序执行,某一个观察者发生错误会导致系统卡壳,一般采用异步方式

简单消息发送示例:

public class Message {
    private String username;

    private String messageContent;

    public String getMessageContent() {
        return messageContent;
    }

    public void setMessageContent(String messageContent) {
        this.messageContent = messageContent;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}


public class WechatPlateform extends Observable {

    private String nameOfPlateform = "WECHAT";

    private static WechatPlateform wechatPlateform = null;

    private WechatPlateform() {
    }

    public static WechatPlateform getInstance() {
        if (wechatPlateform == null) {
            synchronized (WechatPlateform.class) {
                if (wechatPlateform == null) {
                    wechatPlateform = new WechatPlateform();
                }
            }
        }
        return wechatPlateform;
    }

    public String getNameOfPlateform() {
        return nameOfPlateform;
    }

    public void sendMessage(Message message) {
        System.out.println(this.nameOfPlateform + "平台上," + message.getUsername() + "发送了一条消息");
        setChanged();
        notifyObservers(message);
    }
}


public class WeChatUser implements Observer {

    private String username;

    public WeChatUser(String username) {
        this.username = username;
    }

    @Override
    public void update(Observable o, Object arg) {
        WechatPlateform w = (WechatPlateform)o;
        Message message = (Message)arg;
        System.out.println(w.getNameOfPlateform() + ":" + this.username + "收到一条来" + message.getUsername() + "自的消息:");
        System.out.println(message.getMessageContent());

    }

}


public class WechatTest {

    public static void main(String[] args) {
        WeChatUser weChatUser = new WeChatUser("jack");
        WeChatUser weChatUser1 = new WeChatUser("Leonardo DiCaprio");
        Message message = new Message();
        message.setUsername("rose/Kate Winslet");
        message.setMessageContent("oh my god,jack,haven't seen you for a long time,I almost can't recognize you! the "
            + "size of your clothes is getting bigger than ever before!");
        WechatPlateform wechatPlateform = WechatPlateform.getInstance();
        wechatPlateform.addObserver(weChatUser1);
        wechatPlateform.addObserver(weChatUser);
        wechatPlateform.sendMessage(message);
    }
}


运行结果:
WECHAT平台上,rose/Kate Winslet发送了一条消息

WECHAT:jack收到一条来rose/Kate Winslet自的消息:
oh my god,jack,haven't seen you for a long time,I almost can't recognize you! the size of your clothes is getting bigger than ever before!

WECHAT:Leonardo DiCaprio收到一条来rose/Kate Winslet自的消息:
oh my god,jack,haven't seen you for a long time,I almost can't recognize you! the size of your clothes is getting bigger than ever before!




结构关系图如下:

主要的创建步骤:

1、创建WechatPlateform  类,为被观察者,需要绑定观察者【通过继承 java.util.Observable类,其中的Vector<Observer> 属性集合就是用来存储观察者】,SendMessage()方法中调用了父类的notifyObservers()方法,用于通知观察者,并做出相应的操作。

2、创建WechatUser观察者,继承了Observer类,实现update(Observable obs,Object obj)用于对被观察者发生改变后做出对应的操作。

3、创建Message类,消息主体类,可以不加,此处只是方便用于展示。

4、创建客户端调用,就是测试类的main()方法中的内容。

键盘触发事件,示例:

public class Events {
    //事件源,事件的触发者
    private Object source;

    //事件触发通知谁
    private Object target;

    //事件触发后需要做出什么反映,回调函数
    private Method callback;

    //触发的什么事件,时间的名称
    private String trigger;

    //事件触发的时间
    private Date time;

    public static Events getInstance(String trigger, Object source, Object object) {
        Method[] methods = object.getClass().getMethods();
        for (Method method : methods) {
            if (method.getName().equals(trigger)) {
                Events events = new Events();
                events.setSource(source);
                events.setCallback(method);
                events.setTarget(object);
                events.setTrigger(trigger);
                events.setTime(new Date());
                return events;
            }
        }
        return null;
    }

    public 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 void setTrigger(String trigger) {
        this.trigger = trigger;
    }

    public void setTime(Date time) {
        this.time = time;
    }

    @Override
    public String toString() {
        return "Events{\n " + "source=" + source + ",\n target=" + target + ", \n callback=" + callback + ",\n "
            + "trigger='" + trigger + '\'' + ",\n time=" + time + "\n}";
    }
}


public class Listener {

    Map<String, Events> objectMap = null;

    public Listener() {
        this.objectMap = new HashMap<>();
    }

    public void addListener(String trigger, Events object) {
        objectMap.put(trigger, object);
    }

    public void trigger(String trigger) {
        Events t = objectMap.get(trigger);
        t.setSource(this);
        try {
            t.getCallback().invoke(t.getTarget(), t);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}


public enum KeybordEventEnum {
    ENTER("enter", "回车"),

    CAPSLOCK("capsLock", "大写锁定"),

    ESC("esc", "退出"),

    TAB("tab", "制表tab");

    private String eventName;
    private String description;

    KeybordEventEnum(java.lang.String eventName, java.lang.String description) {
        this.eventName = eventName;
        this.description = description;
    }

    public String getEventName() {
        return eventName;
    }
}


public class KeybordCallback {

    public void enter(Events events) {
        System.out.println("=======callback点击回车按钮:\n" + events);
    }

    public void capsLock(Events events) {
        System.out.println("=======callback点击大写锁定按钮:\n" + events);
    }

    public void esc(Events events) {
        System.out.println("=======callback点击退出esc按钮:\n" + events);
    }

    public void tab(Events events) {
        System.out.println("=======callback点击tab按钮:\n" + events);
    }

}


public class KeybordTest {
    public static void main(String[] args) {
        KeybordCallback callback = new KeybordCallback();
        Keybord keybord = new Keybord();
        keybord.addListener(KeybordEventEnum.ENTER.getEventName(),callback);
        keybord.addListener(KeybordEventEnum.CAPSLOCK.getEventName(),callback);
        keybord.addListener(KeybordEventEnum.ESC.getEventName(),callback);
        keybord.addListener(KeybordEventEnum.TAB.getEventName(),callback);
        keybord.capsLock();
        keybord.enter();
        keybord.esc();
        keybord.tab();
    }
}


执行结果:
点击大写锁定按钮:
=======callback点击大写锁定按钮:
Events{
 source=com.tealala.pattern.observer.events1.core.Keybord@31befd9f,
 target=com.tealala.pattern.observer.events1.core.KeybordCallback@1c20c684, 
 callback=public void com.tealala.pattern.observer.events1.core.KeybordCallback.capsLock(com.tealala.pattern.observer.events1.core.Events),
 trigger='capsLock',
 time=Fri Dec 20 17:10:49 CST 2019
}

点击回车按钮:
=======callback点击回车按钮:
Events{
 source=com.tealala.pattern.observer.events1.core.Keybord@31befd9f,
 target=com.tealala.pattern.observer.events1.core.KeybordCallback@1c20c684, 
 callback=public void com.tealala.pattern.observer.events1.core.KeybordCallback.enter(com.tealala.pattern.observer.events1.core.Events),
 trigger='enter',
 time=Fri Dec 20 17:10:49 CST 2019
}

点击退出esc按钮:
=======callback点击退出esc按钮:
Events{
 source=com.tealala.pattern.observer.events1.core.Keybord@31befd9f,
 target=com.tealala.pattern.observer.events1.core.KeybordCallback@1c20c684, 
 callback=public void com.tealala.pattern.observer.events1.core.KeybordCallback.esc(com.tealala.pattern.observer.events1.core.Events),
 trigger='esc',
 time=Fri Dec 20 17:10:49 CST 2019
}

点击tab按钮:
=======callback点击tab按钮:
Events{
 source=com.tealala.pattern.observer.events1.core.Keybord@31befd9f,
 target=com.tealala.pattern.observer.events1.core.KeybordCallback@1c20c684, 
 callback=public void com.tealala.pattern.observer.events1.core.KeybordCallback.tab(com.tealala.pattern.observer.events1.core.Events),
 trigger='tab',
 time=Fri Dec 20 17:10:49 CST 2019
}
发布了35 篇原创文章 · 获赞 0 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/tealala/article/details/103627377