介紹
觀察者模式也被稱為發(fā)布-訂閱(Publish/Subscribe)模式尤仍,它屬于行為型模式的一種。觀察者模式定義了一種一對多的依賴關(guān)系窜管,一個(gè)主題對象可被多個(gè)觀察者對象同時(shí)監(jiān)聽揩尸。當(dāng)這個(gè)主題對象狀態(tài)變化時(shí)宛渐,會(huì)通知所有觀察者對象并作出相應(yīng)處理邏輯界斜。
UML
觀察者模式定義了四種角色:抽象主題仿耽、具體主題、抽象觀察者各薇、具體觀察者项贺。
- 抽象主題(Subject):該角色是一個(gè)抽象類或接口,定義了增加得糜、刪除敬扛、通知觀察者對象的方法。
- 具體主題(ConcreteSubject):該角色繼承或?qū)崿F(xiàn)了抽象主題朝抖,定義了一個(gè)集合存入注冊過的具體觀察者對象啥箭,在具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),給所有注冊過的觀察者發(fā)送通知治宣。
- 抽象觀察者(Observer):該角色是具體觀察者的抽象類急侥,定義了一個(gè)更新方法。
-
具體觀察者(ConcrereObserver):該角色是具體的觀察者對象侮邀,在得到具體主題更改通知時(shí)更新自身的狀態(tài)坏怪。
</br>
</br>
實(shí)現(xiàn)代碼
抽象觀察者(Observer)接口
public interface Observer {
public void update(String msg, TextView tv);
}
具體觀察者(Person)類
public class Person implements Observer {
// 用戶名
private String name;
public Person(String name) {
this.name = name;
}
@Override
public void update(String msg, TextView tv) {
tv.setText(tv.getText()+name+":"+ msg +"\n");
}
}
抽象主題(Subject)接口
public interface Subject {
/**
* 增加觀察者
* @param observer
*/
public void attach(Observer observer);
/**
* 刪除觀察者
* @param observer
*/
public void detach(Observer observer);
/**
* 通知觀察者
*/
public void notify(String message, TextView v);
}
具體主題(XiaosongSubject)類
public class XiaosongSubject implements Subject {
//用于保存訂閱了小嵩的博客的用戶
private List<Observer> mPersonList = new ArrayList<>();
@Override
public void attach(Observer observer) {
mPersonList.add(observer);
}
@Override
public void detach(Observer observer) {
mPersonList.remove(observer);
}
@Override
public void notify(String message, TextView tv) {
for (Observer observer : mPersonList) {
observer.update(message,tv);
}
}
}
MainActivity類
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Person pMing,pQing,pLiang;
private XiaosongSubject mSubject;
private TextView tv_output;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initEvent();
}
private void initView() {
findViewById(R.id.btn_add_one).setOnClickListener(this);
findViewById(R.id.btn_add_two).setOnClickListener(this);
findViewById(R.id.btn_add_three).setOnClickListener(this);
findViewById(R.id.btn_notify).setOnClickListener(this);
findViewById(R.id.btn_delete).setOnClickListener(this);
tv_output = (TextView)findViewById(R.id.tv_output);
}
private void initEvent() {
//創(chuàng)建被觀察者(具體主題)
mSubject = new XiaosongSubject();
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_add_one://注冊觀察者 小明
if (pMing==null){
pMing = new Person("小明");
mSubject.attach(pMing);
Toast.makeText(this,"小明關(guān)注了我",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this,"小明已關(guān)注我了,不能再重復(fù)操作",Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_add_two://注冊觀察者 小琴
if (pQing==null){
pQing = new Person("小琴");
mSubject.attach(pQing);
Toast.makeText(this,"小琴關(guān)注了我",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this,"小琴已關(guān)注我了绊茧,不能再重復(fù)操作",Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_add_three://注冊觀察者 阿亮
if (pLiang==null){
pLiang = new Person("阿亮");
mSubject.attach(pLiang);
Toast.makeText(this,"阿亮關(guān)注了我",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this,"阿亮已關(guān)注我了铝宵,不能再重復(fù)操作",Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_notify://主題(被觀察者)更新了內(nèi)容,通知所有觀察者
tv_output.setText("");
mSubject.notify("小嵩更新微博啦~ 快來看看吧", tv_output);
break;
case R.id.btn_delete://注銷觀察者 小明
if (pMing!=null){
mSubject.detach(pMing);
pMing = null;
}
if (pQing!=null){//注銷觀察者 小琴
mSubject.detach(pQing);
pQing = null;
}
if (pLiang!=null){//注銷觀察者 阿亮
mSubject.detach(pLiang);
pLiang = null;
}
break;
default:
break;
}
}
}
總結(jié)
在Android中华畏,有很多場景使用了觀察者模式鹏秋,比如Android的源碼里:OnClickListener、ContentObserver亡笑、android.database.Observable等侣夷;還有第三方開源庫EventBus、RxJava仑乌、RxAndroid等百拓。具體可閱讀它們的源碼去理解和體會(huì)。這里我寫了一個(gè)簡單的demo晰甚,以便對它有更加深刻的理解衙传,覺得這篇文章有用的話,可以點(diǎn)個(gè)贊哦~
GitHub的示例項(xiàng)目鏈接地址:ObserverPatternDemo