转自http://www.eoeandroid.com/home.php?mod=space&uid=871316&do=blog&id=48239
最近在学习下设计模式,而加深学习的不错的方法就是把心得写出来吧。记录下自己的理解。现在自己看的书是《head.Frist设计模式》这本书。比较不错,想学习设计模式的朋友可以看下这本书。
观察者<Observer>模式(有时又被称为发布-订阅<Publish/Subscribe>模式、模型-视图<Model/View>模式、源-收听者<Source/Listener>模式或从属者<Dependents>模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。(源自百度百科)
(五月三十一号修正内容)
看下结构图:
开始一个小例子
Observer接口:
- public interface ISubscribe {
- void getNewPaper();
- }
实现Observer接口的观察者:
个人订阅者:
- public class PersonalSubscriber implements ISubscribe {
- private String strName;
- public void setNewsPaperName(String strName){
- this.strName = strName;
- }
- public String getNewsPaperName(){
- return strName;
- }
- @Override
- public void getNewPaper() {
- // TODO Auto-generated method stub
- System.out.println("我是个人用户,我得到了我的报纸:"+getNewsPaperName());
- }
- }
企业订阅者:
- public class EnterpriseSubscriber implements ISubscribe {
- private String strName;
- public void setNewsPaperName(String strName){
- this.strName = strName;
- }
- public String getNewsPaperName(){
- return strName;
- }
- @Override
- public void getNewPaper() {
- // TODO Auto-generated method stub
- System.out.println("我是企业用户,我得到了我的报纸:"+getNewsPaperName());
- }
- }
被观察者:Subject
- public abstract class Publish {
- public List<ISubscribe> list;
- public Publish(){
- list = new ArrayList();
- }
- public void registered(ISubscribe iSubscribe){
- list.add(iSubscribe);
- }
- public void unregistered(ISubscribe iSubscribe){
- list.remove(iSubscribe);
- }
- public abstract void sendNewsPaper();
- }
这里使用的是抽象类
下面是实现:
- public class PostOffice extends Publish{
- @Override
- public void sendNewsPaper() {
- // TODO Auto-generated method stub
- Iterator iterator = list.iterator();
- while(iterator.hasNext()){
- ((ISubscribe) iterator.next()).getNewPaper();
- }
- }
- }
测试:
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- PostOffice postOffice = new PostOffice();
- //得到个人用户
- PersonalSubscriber person = new PersonalSubscriber();
- person.setNewsPaperName("《南方周末》");
- //得到企业用户
- EnterpriseSubscriber enterprise = new EnterpriseSubscriber();
- enterprise.setNewsPaperName("《企业报》");
- //注册观察者
- postOffice.registered(person);
- postOffice.registered(enterprise);
- //发放报纸
- postOffice.sendNewsPaper();
- }
测试结果:
- 我是个人用户,我得到了我的报纸:《南方周末》
- 我是企业用户,我得到了我的报纸:《企业报》
下面是有些错误五月18号版本:后面有错误解析!
举个例子,张三从邮局订阅了《南方周末》,李四从邮局订阅了《新京报》,王五从邮局里面订阅了《南方都市报》。当报纸抵达邮局的时候,邮局就会把报纸送递订阅者。而不需要订阅者天天到邮局询问报纸是否到达邮局。
下面开始代码:首先应该是个订阅者接口:
- package cn.demo;
- public interface ISubscribe {
- //从邮局订阅报纸
- public void registered(PostOffice postOffice);
- //从邮局退订报纸
- public void unregistered(PostOffice postOffice);
- //获取报纸名称
- public void getNewsPaper();
- }
第三个方法非必须,前两个方法必须要有。(应修改为前两个非必须,第三个方法必须有)
然后有三个订阅者类:
张三:
- package cn.demo;
- public class ZhangSan implements ISubscribe{
- private String mName;
- private String mNewsPaperName;
- public ZhangSan(String mName, String mNewsPaperName) {
- this.mName = mName;
- this.mNewsPaperName = mNewsPaperName;
- }
- public String getName() {
- return mName;
- }
- public String getNewsPaperName() {
- return mNewsPaperName;
- }
- @Override
- public void registered(PostOffice postOffice){
- postOffice.registeredNewsPaper(this);
- }
- @Override
- public void unregistered(PostOffice postOffice){
- postOffice.unregisteredNewsPaper(this);
- }
- @Override
- public void getNewsPaper() {
- // TODO Auto-generated method stub
- System.out.println("我是"+getName()+",我收到我订阅的"+getNewsPaperName());
- }
- }
李四:
- package cn.demo;
- public class Lisi implements ISubscribe{
- private String mName;
- private String mNewsPaperName;
- public Lisi(String mName, String mNewsPaperName) {
- this.mName = mName;
- this.mNewsPaperName = mNewsPaperName;
- }
- public String getName() {
- return mName;
- }
- public String getNewsPaperName() {
- return mNewsPaperName;
- }
- @Override
- public void unregistered(PostOffice postOffice){
- postOffice.unregisteredNewsPaper(this);
- }
- @Override
- public void registered(PostOffice postOffice){
- postOffice.registeredNewsPaper(this);
- }
- @Override
- public void getNewsPaper() {
- // TODO Auto-generated method stub
- System.out.println("我是"+getName()+",我收到我订阅的"+getNewsPaperName());
- }
- }
王五:
- package cn.demo;
- public class Wangwu implements ISubscribe{
- private String mName;
- private String mNewsPaperName;
- public Wangwu(String mName, String mNewsPaperName) {
- this.mName = mName;
- this.mNewsPaperName = mNewsPaperName;
- }
- public String getName() {
- return mName;
- }
- public String getNewsPaperName() {
- return mNewsPaperName;
- }
- @Override
- public void registered(PostOffice postOffice){
- postOffice.registeredNewsPaper(this);
- }
- @Override
- public void unregistered(PostOffice postOffice){
- postOffice.unregisteredNewsPaper(this);
- }
- @Override
- public void getNewsPaper() {
- // TODO Auto-generated method stub
- System.out.println("我是"+getName()+",我收到我订阅的"+getNewsPaperName());
- }
- }
三个订阅者,都有方法订阅报纸,或者取消订阅。其实关于订阅者的信息,是存储在邮局类里面。
- import java.util.ArrayList;
- import java.util.List;
- public class PostOffice {
- private List<ISubscribe> SubscribeList = new ArrayList<ISubscribe>();
- public void registeredNewsPaper(ISubscribe subscribe) {
- SubscribeList.add(subscribe);
- }
- public void unregisteredNewsPaper(ISubscribe subscribe) {
- if (subscribe != null) {
- SubscribeList.remove(subscribe);
- }
- }
- public void getNewsPaper(boolean bool) {
- if (bool) {
- sendNewsPaper();
- }
- }
- public void sendNewsPaper() {
- for(ISubscribe subscribe : SubscribeList) {
- subscribe.getNewsPaper();
- }
- }
- }
测试类:
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- PostOffice mPostOffice = new PostOffice();
- ISubscribe zhangsan = new ZhangSan("张三", "《南方周末》");
- ISubscribe lisi = new Lisi("李四", "《新京报》");
- ISubscribe wangwu = new Wangwu("王五", "《南方都市报》");
- //开始订阅报纸
- zhangsan.registered(mPostOffice);
- lisi.registered(mPostOffice);
- wangwu.registered(mPostOffice);
- //邮局收到报纸,开始发放
- mPostOffice.getNewsPaper(true);
- //李四退订
- lisi.unregistered(mPostOffice);
- //邮局收到报纸,开始发放
- mPostOffice.getNewsPaper(true);
- }
打印结果:
- 我是张三,我收到我订阅的《南方周末》
- 我是李四,我收到我订阅的《新京报》
- 我是王五,我收到我订阅的《南方都市报》
- 我是张三,我收到我订阅的《南方周末》
- 我是王五,我收到我订阅的《南方都市报》
这里只是提供了一个简单的例子,而且代码你会发现有冗余,三个订阅者类,几乎是一样,因为没有在类里面添加他们独自的属性,可以用一个Person类来替代。这里写这三个类是为了显示清晰。
关于五月18号的例子,观察者没必要有注册和取消注册的方法。他们的方法的实现也是调用的被观察者的注册和取消注册,不如直接使用被观察者的方法。
在Android中,button.setOnclickListener()这个方式是比较常见的观察者模式:当然,众所周知,onClick是著名的回调方法,在这里不会研究回调,不用太在意。
看下代码:
- Button button1 = (Button)findViewById(R.id.button1);
- Button button2 = (Button)findViewById(R.id.button2);
- Button button3 = (Button)findViewById(R.id.button3);
- button1.setOnClickListener(this);
- button2.setOnClickListener(this);
- button3.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- switch(v.getId()) {
- case R.id.button1 :
- // do some thing
- case R.id.button2 :
- // do some thing
- case R.id.button3 :
- // do some thing
- }
- }
先button.setOnclickListener()进行注册。相当于邮局中的lisi.registered(mPostOffice),此处错误,应该是第一例中的postOffice.registered(person)。onclick响应事件相当于邮局中的
- public void sendNewsPaper() {
- for(ISubscribe subscribe : SubscribeList) {
- subscribe.getNewsPaper();
- }
- }
这个中的subscribe.getNewsPaper()这个方法。View.onClickListener相当于邮局。View也就是button是我们的订阅者,也就相当于张三。我们也可以在getNewsPaper中加一些自己的switch判断。
最后,如果我们的邮局要实现类似button这样的回调这么实现呢?
- ISubscribe isubscribe;
- @Override
- public void getNewsPaper() {
- // TODO Auto-generated method stub
- System.out.println("我是"+getName()+",我收到我订阅的"+getNewsPaperName());
- isubscribe.getNewsPaper();
- }