觀察者模式

觀察者模式

定義

定義對象間一種一對多的依賴關係,使得當一個對象改變狀態,因此依賴它的對象都會收到通知並被自動更新。java

使用場景

  • 事件多級觸發場景
  • 跨系統的消息交互場景,消息隊列、事件總線、廣播
  • 關聯行爲場景、一對多且變化頻繁的場景、如UI改變

結構

  • Subject

抽象主題,也就是被觀察者Observable,把全部觀察者對象的引用保存在一個集合裏,每一個主題均可以有任意數量的觀察者,會提供接口來增長和刪除觀察者對象bash

  • ConcreateSubject框架

    具體主題,將有關狀態存入具體觀察者對象,在具體主題對象內部發生變化時,給全部註冊過的觀察者發送通知ide

  • Observerui

    抽象觀察者,定義更新接口,使得在獲得主題更改的通知時候更新本身this

  • ConcreateObserverspa

    具體觀察者,實現抽象觀察者角色定義的更新接口code

JDK中已經內置了抽象主題對象Observable和抽象觀察者對象Observer,能夠直接使用server

簡單實現

//抽象目標類,被觀察者
public abstract class Login {
    protected ArrayList observers = new ArrayList();

    public abstract void register(LoginObserver observer);

    public abstract void unregister(LoginObserver observer);

    public abstract void loginNotify(UserBean loginBean);

    public abstract void exitNotify();

}

複製代碼
//抽象觀察者類
public interface LoginObserver {

    void login(UserBean loginBean);//登陸成功

    void exit();//退出登陸
}

複製代碼
//具體目標類,具體目標類的變更將引起具體觀察者類作出相應的動做
public class ConcreteLogin extends Login {

    private static ConcreteLogin concreteLogin;

    public static ConcreteLogin getInstance() {
        if (concreteLogin == null) {
            synchronized (ConcreteLogin.class) {
                if (concreteLogin == null) {
                    concreteLogin = new ConcreteLogin();
                }
            }
        }

        return concreteLogin;
    }


    @Override
    public void register(LoginObserver observer) {
        observers.add(observer);
    }

    @Override
    public void unregister(LoginObserver observer) {
        observers.remove(observer);
    }

    @Override
    public void loginNotify(UserBean loginBean) {
        String password = loginBean.getPassword();
        String userName = loginBean.getUserName();

        Boolean success = false;
        //模擬登陸
        if (password.contains("123") && userName.contains("123")) {
            success = true;
        }

        for (Object obs : observers) {
            LoginObserver loginObserver = (LoginObserver) obs;
            if (success) {
                Log.v(getClass().getSimpleName(), "登陸成功");
                loginObserver.login(loginBean);
            } else {
                Log.v(getClass().getSimpleName(), "登陸失敗");
            }
        }

    }

    @Override
    public void exitNotify() {
        Log.v(getClass().getSimpleName(), "退出登陸");
        for (Object obs : observers) {
            LoginObserver loginObserver = (LoginObserver) obs;
            loginObserver.exit();
        }
    }
}

複製代碼
//具體觀察者2
public class ObserverActivity2 extends AppCompatActivity implements LoginObserver, View.OnClickListener {
    TextView account, pwd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_observer2);

        account = (TextView) findViewById(R.id.account);
        pwd = (TextView) findViewById(R.id.pwd);

        ConcreteLogin.getInstance().register(this);

        findViewById(R.id.bt_login).setOnClickListener(this);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ConcreteLogin.getInstance().unregister(this);
    }


    @Override
    public void login(UserBean loginBean) {
        //登陸用戶信息變更   UI作出相應調整
        account.setText(loginBean.getPassword());
        pwd.setText(loginBean.getUserName());
        //對用戶數據作出相應處理  ...
    }

    @Override
    public void exit() {
        account.setText("");
        pwd.setText("");
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_login:
                Intent intent = new Intent();
                intent.setClass(this, LoginControlActivity.class);
                startActivity(intent);
                break;
            default:
                break;
        }
    }
}

複製代碼

LoginControlActivity關鍵代碼對象

public void doLogin(View view) {
        UserBean loginBean = new UserBean(getUserName(), getPwd());
        ConcreteLogin.getInstance().loginNotify(loginBean);
    }


    public void doExit(View view) {
        ConcreteLogin.getInstance().exitNotify();
    }
複製代碼

當執行doLogin()方法時,若是登陸成功,則全部註冊了註冊過的觀察者對象都將收到通知,即會執行LoginObserver接口的login()回調,從而來執行UI更新等邏輯。

使用觀察者模式,記得在不須要使用的時候將觀察者註銷掉,不然容易形成內存泄露

小結

觀察者模式最大的特色就是對象的解耦,觀察者與被觀察徹底隔離,只依賴於Observer和Observable抽象;

觀察者模式的思想被衆多框架和控制吸取,如 Rxjava事件流、Eventbus消息監聽、Listview和RecyclerView的Adapter更新ui、廣播、事件機制等

相關文章
相關標籤/搜索