定義對象間一種一對多的依賴關係,使得當一個對象改變狀態,因此依賴它的對象都會收到通知並被自動更新。java
抽象主題,也就是被觀察者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、廣播、事件機制等