观察者模式:
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。例如拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。
观察者模式提供了一种对象设计, 让主题和观察者之间松耦合。主题只知道观察者实现了某个接口(也就是Observer接口)。主题不需要知道观察者的具体类是谁、做了些什么或其他任何细节。任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。同样我们也可以删除观察者。有新类型的观察者出现时,主题的代码不需要修改。它只会发送通知给所有实现了观察者接口的对象。
本次选择项目为:一个实现简易微博关注/取关,发布微博内容/接收关注人更博通知功能的app项目。
项目Github地址:https://github.com/xiaosong520/ObserverPatternDemo
项目基础类如下
现在按观察者模式中对应类进行学习
抽象观察者(Observer)接口
在Observer.java中定义了抽象观察者类
public interface Observer { public void update(String msg, TextView tv); }
具体观察者(Person)类
在Person.java中实现了具体观察者类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)接口
在Subject.java中定义了抽象目标类,定义了观察者的方法
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)类
在XiaosongSubject.java中定义了具体目标类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() { //创建被观察者(具体主题) 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,"小明关注了我",Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this,"小明已关注我了,不能再重复操作",Toast.LENGTH_SHORT).show(); } break; case R.id.btn_add_two://注册观察者 小琴 if (pQing==null){ pQing = new Person("小琴"); mSubject.attach(pQing); Toast.makeText(this,"小琴关注了我",Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this,"小琴已关注我了,不能再重复操作",Toast.LENGTH_SHORT).show(); } break; case R.id.btn_add_three://注册观察者 阿亮 if (pLiang==null){ pLiang = new Person("阿亮"); mSubject.attach(pLiang); Toast.makeText(this,"阿亮关注了我",Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this,"阿亮已关注我了,不能再重复操作",Toast.LENGTH_SHORT).show(); } break; case R.id.btn_notify://主题(被观察者)更新了内容,通知所有观察者 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; } } }
demo演示