java設(shè)計(jì)模式--觀察者模式

觀察者模式

觀察者--OOD線程

簡單理解

起一個(gè)被觀察者線程和一個(gè)觀察者線程。觀察者不斷的循環(huán)檢查被觀察者狀態(tài)是否發(fā)生改變。此設(shè)計(jì)缺點(diǎn),因?yàn)樾枰粩嗟难h(huán)進(jìn)行監(jiān)視,所以耗CPU資源。

舉例場景

孩子在睡覺,醒后要吃東西,父親不斷的監(jiān)視者看孩子有沒有醒

代碼實(shí)現(xiàn)

child


package observersOOD;
/**
 * 觀察者模式-OOD線程
 * 起一個(gè)被觀察者線程和一個(gè)觀察者線程。觀察者不斷的循環(huán)檢查被觀察者狀態(tài)是否發(fā)生改變
 * 案例:孩子在睡覺,醒后要吃東西,父親不斷的監(jiān)視者看孩子有沒有醒
 */

public class Child implements Runnable{

    private boolean wakenUp = false;

    public boolean isWakenUp() {
        return wakenUp;
    }

    public void setWakenUp(boolean wakenUp) {
        this.wakenUp = wakenUp;
    }

    public void wakeUp(){
        System.out.println("孩子醒了....");
        wakenUp = true;
    }

    public void run() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        wakeUp();

    }
}

Dad類

package observersOOD;

public class Dad implements Runnable {

    private Child child;

    public Dad(Child child) {
        this.child = child;
    }

    public void  feed(Child child){
        System.out.println("feed child......");
    }

    public void run() {
        while (!child.isWakenUp()){
            try {
                System.out.println("我在監(jiān)視孩子。。。。");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        feed(this.child);
    }

    public static void main(String[] args) {
        Child child = new Child();
        Dad dad = new Dad(child);
        Thread childThread = new Thread(child);
        Thread dadThread = new Thread(dad);
        childThread.start();
        dadThread.start();
    }
}

test

 public static void main(String[] args) {
        Child child = new Child();
        Dad dad = new Dad(child);
        Thread childThread = new Thread(child);
        Thread dadThread = new Thread(dad);
        childThread.start();
        dadThread.start();
    }

運(yùn)行結(jié)果

我在監(jiān)視孩子。。。。
我在監(jiān)視孩子。。。。
我在監(jiān)視孩子。。。。
我在監(jiān)視孩子。。。。
孩子醒了....
feed child......

改進(jìn)(上面由于父類需要主動(dòng)監(jiān)視孩子,需要通過不斷的循環(huán)實(shí)現(xiàn),太浪費(fèi)資源)。

改進(jìn)后有孩子醒后主動(dòng)通知父親。

class Child implements Runnable {
     
    private Dad dad;
     
    public Child(Dad dad) {
        this.dad = dad;
    }
 
    public void wakeUp(){
        dad.feed(this);
    }
 
    @Override
    public void run() {
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        wakeUp();
    }
}
 
class Dad {
 
    void feed(Child c) {
        System.out.println("feed child");
    }
     
}
 
public class Test {
 
    public static void main(String[] args) {
        Dad d = new Dad();
        Child c = new Child(d);
        new Thread(c).start();
    }
}

把孩子睡醒后封裝成事件

class WakenUpEvent{
     
    private long time;
    private String location;
    private Child source;
     
    public WakenUpEvent(long time, String location, Child source) {
        super();
        this.time = time;
        this.location = location;
        this.source = source;
    }
 
    public long getTime() {
        return time;
    }
 
    public void setTime(long time) {
        this.time = time;
    }
 
    public String getLocation() {
        return location;
    }
 
    public void setLocation(String location) {
        this.location = location;
    }
 
    public Child getSource() {
        return source;
    }
 
    public void setSource(Child source) {
        this.source = source;
    }
     
     
}
class Child implements Runnable {
     
    private Dad dad;
     
    public Child(Dad dad) {
        this.dad = dad;
    }
 
    public void wakeUp(){
        dad.actionToWakenUp(new WakenUpEvent(System.currentTimeMillis(), "bed", this));
    }
 
    @Override
    public void run() {
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        wakeUp();
    }
}
 
class Dad {
 
    public void actionToWakenUp(WakenUpEvent e) {
        System.out.println(e.getTime());
        System.out.println(e.getLocation());
        System.out.println(e.getSource());
        System.out.println("Fedd the child");
    }
     
}
 
public class Test {
 
    public static void main(String[] args) {
        Dad d = new Dad();
        Child c = new Child(d);
        new Thread(c).start();
    }
}

上面例子中child都會(huì)持有dad類,如果觀察者發(fā)生改變,需要修改代碼很不方便。

解決方法:動(dòng)態(tài)的注冊到被觀察者中。持有addListener方法
定義監(jiān)聽者接口

interface WakenUpListener {
    public void actionToWakenUp(WakenUpEvent e);
}

定義實(shí)際監(jiān)聽者


class Dad implements WakenUpListener {
 
    public void actionToWakenUp(WakenUpEvent e) {
        System.out.println("Fedd the child");
    }
     
}

class GrandFather implements WakenUpListener {
 
    public void actionToWakenUp(WakenUpEvent e) {
        System.out.println("抱孩子");
    }
     
}

定義child,child中持有添加觀察者方法,當(dāng)醒后一一通知他的觀察者

package observersOOD.Listener;

import java.util.ArrayList;
import java.util.List;

public class Child implements Runnable{

    public Child() {
    }

    private List<WakenUpListener> wakenUpListeners = new ArrayList<WakenUpListener>();

    //提供一個(gè)注冊觀察者方法
    public void  addWakenUpListener(WakenUpListener wakenUpListener){
        wakenUpListeners.add(wakenUpListener);
    }

    //提供一個(gè)通知方法
    public void wakeUp(){
        for (int i=0;i<wakenUpListeners.size();i++){
            WakenUpEvent wakenUpEvent = new WakenUpEvent(111111L,"111111",this);
            wakenUpListeners.get(i).actionToWakenUp(new WakenUpEvent(1111L,"1111",this));
        }
    }



    public void run() {
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        wakeUp();

    }
}

定義Test類

package observersOOD.Listener;

public class Test {
    public static void main(String[] args) {

        WakenUpListener dad = new Dad();
        WakenUpListener grandFather = new GrandFather();

        Child child = new Child();
        child.addWakenUpListener(dad);
        child.addWakenUpListener(grandFather);

        Thread thread = new Thread(child);
        thread.start();
    }
}

運(yùn)行結(jié)果

1111
1111
開始喂孩子....
抱孩子......

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容