设计模式之观察者模式

设计模式 之 观察者模式

观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

-- 阎宏博士的《JAVA与模式》


 

例:Button事件模型

第一版:以最简单的方式实现Button被按下时处理自己的业务

一个普通的Button,当被按下时将自己的pressed状态改为true
 1 public class MyButton {
 2     private boolean pressedState = false;
 3     
 4     public boolean isPressed() {
 5         return pressedState;
 6     }
 7     
 8     public void pressed() {
 9         pressedState = true;
10     }
11 }
View Code
要想在Button按下后处理自己的业务,则必须启动一个线程不断查看Button的状态
public class Business implements Runnable {
    private MyButton btn;
    public Business(MyButton btn) {
        this.btn = btn;
    }
    
    @Override
    public void run() {
        while(!btn.isPressed()) {
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        process();
    }
    
    private void process() {
        System.out.println("Button pressed!");
    }
}
View Code
测试
1 public class Test {
2     public static void main(String[] args) throws InterruptedException {
3         MyButton btn = new MyButton();
4         Business business = new Business(btn);
5         new Thread(business).start();
6         TimeUnit.SECONDS.sleep(3);
7         btn.pressed();
8     }
9 }
View Code

 OK,虽然满足了需求,但很浪费资源,因为所有等待该Button按下时处理业务的对象必须启动一个线程实时看看Button的状态。

第二版:改进第一版,当Button被按下时通知需要做出响应的业务

Button里增加对业务的引用,用于被按下时通知业务做出响应
public class MyButton {
    private boolean pressedState = false;
    
    private Business business;
    
    public MyButton(Business business) {
        this.business = business;
    }
    
    public boolean isPressed() {
        return pressedState;
    }
    
    public void pressed() {
        pressedState = true;
        business.process();
    }
}
View Code
此时,业务这块需提供对Button被按下时的响应
public class Business {
    public void process() {
        System.out.println("Button pressed!");
    }
}
View Code
测试
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Business business = new Business();
        MyButton btn = new MyButton(business);
        TimeUnit.SECONDS.sleep(3);
        btn.pressed();
    }
}
View Code

OK,这时效率问题已经不存在了,可是现实中,Business不可能都一样,且很多情况下需要根据Button按下的时间,事件源做出不同的响应。

第三版:抽象封装

封装一个事件源
public class ActionEvent {
    long when;
    Object source;
    
    public ActionEvent(long when, Object source) {
        super();
        this.when = when;
        this.source = source;
    }
    
    public long getWhen() {
        return System.currentTimeMillis();
    }
    
    public Object getSource() {
        return source;
    }
}
View Code
抽象出需要对Button被按下时做出响应的业务接口
public interface ActionListener {
    public void actionPerformed(ActionEvent e);
}
View Code
需要对Button被按下做出响应的业务
public class Business implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button pressed! --" + e.getWhen());
    }
}
View Code
重新封装Button
public class MyButton {
    private List<ActionListener> actionListeners = new ArrayList<ActionListener>();
    
    private boolean pressedState = false;
    
    public void addActionListeners(ActionListener l) {
        actionListeners.add(l);
    }
    
    public boolean isPressed() {
        return pressedState;
    }
    
    public void pressed() {
        pressedState = true;
        ActionEvent e = new ActionEvent(System.currentTimeMillis(), this);
        for(int i=0; i<actionListeners.size(); i++) {
            ActionListener l = actionListeners.get(i);
            l.actionPerformed(e);
        }
    }
}
View Code
测试
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Business business = new Business();
        MyButton btn = new MyButton();
        btn.addActionListeners(business);
        TimeUnit.SECONDS.sleep(3);
        btn.pressed();
    }
}
View Code

 OK,这就是JDK中事件的处理逻辑,也是观察者模式的完美应用。

作者:踮起脚尖眺望
出处:http://www.cnblogs.com/wangj1130
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/wangj1130/p/4822597.html