浅学设计模式之观察者<Observer>模式及在android中的应用

简介:

转自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接口:

     

  1. public interface ISubscribe {  
  2.     void getNewPaper();  
  3. }  

实现Observer接口的观察者:

个人订阅者:

  1. public class PersonalSubscriber implements ISubscribe {  
  2.     private String strName;  
  3.       
  4.     public void setNewsPaperName(String strName){  
  5.         this.strName = strName;  
  6.     }  
  7.       
  8.     public String getNewsPaperName(){  
  9.         return strName;  
  10.     }  
  11.   
  12.     @Override  
  13.     public void getNewPaper() {  
  14.         // TODO Auto-generated method stub  
  15.         System.out.println("我是个人用户,我得到了我的报纸:"+getNewsPaperName());  
  16.     }  
  17.   
  18. }  

企业订阅者:

  1. public class EnterpriseSubscriber implements ISubscribe {  
  2.     private String strName;  
  3.       
  4.     public void setNewsPaperName(String strName){  
  5.         this.strName = strName;  
  6.     }  
  7.       
  8.     public String getNewsPaperName(){  
  9.         return strName;  
  10.     }  
  11.     @Override  
  12.     public void getNewPaper() {  
  13.         // TODO Auto-generated method stub  
  14.         System.out.println("我是企业用户,我得到了我的报纸:"+getNewsPaperName());  
  15.     }  
  16.   
  17. }  

被观察者:Subject

  1. public abstract class Publish {   
  2.     public List<ISubscribe> list;  
  3.     public Publish(){  
  4.         list = new ArrayList();  
  5.     }  
  6.       
  7.     public void registered(ISubscribe iSubscribe){  
  8.         list.add(iSubscribe);  
  9.     }  
  10.       
  11.     public void unregistered(ISubscribe iSubscribe){  
  12.         list.remove(iSubscribe);  
  13.     }  
  14.       
  15.     public abstract void sendNewsPaper();  
  16. }  

这里使用的是抽象类

下面是实现:

  1. public class PostOffice extends Publish{  
  2.   
  3.     @Override  
  4.     public void sendNewsPaper() {  
  5.         // TODO Auto-generated method stub  
  6.         Iterator iterator = list.iterator();  
  7.         while(iterator.hasNext()){  
  8.             ((ISubscribe) iterator.next()).getNewPaper();  
  9.         }  
  10.     }  
  11.       
  12. }  

测试:

  1. public static void main(String[] args) {  
  2.         // TODO Auto-generated method stub  
  3.         PostOffice postOffice = new PostOffice();  
  4.           
  5.         //得到个人用户  
  6.         PersonalSubscriber person = new PersonalSubscriber();  
  7.         person.setNewsPaperName("《南方周末》");  
  8.         //得到企业用户  
  9.         EnterpriseSubscriber enterprise = new EnterpriseSubscriber();  
  10.         enterprise.setNewsPaperName("《企业报》");  
  11.           
  12.         //注册观察者  
  13.         postOffice.registered(person);  
  14.         postOffice.registered(enterprise);  
  15.           
  16.         //发放报纸  
  17.         postOffice.sendNewsPaper();  
  18.     }  

测试结果:

  1. 我是个人用户,我得到了我的报纸:《南方周末》  
  2. 我是企业用户,我得到了我的报纸:《企业报》  



下面是有些错误五月18号版本:后面有错误解析!

        举个例子,张三从邮局订阅了《南方周末》,李四从邮局订阅了《新京报》,王五从邮局里面订阅了《南方都市报》。当报纸抵达邮局的时候,邮局就会把报纸送递订阅者。而不需要订阅者天天到邮局询问报纸是否到达邮局。

       下面开始代码:首先应该是个订阅者接口:

  1. package cn.demo;  
  2.   
  3. public interface ISubscribe {  
  4.     //从邮局订阅报纸  
  5.     public void registered(PostOffice postOffice);  
  6.     //从邮局退订报纸  
  7.     public void unregistered(PostOffice postOffice);  
  8.     //获取报纸名称  
  9.     public void getNewsPaper();  
  10. }  

第三个方法非必须,前两个方法必须要有。(应修改为前两个非必须,第三个方法必须有)

然后有三个订阅者类:

张三:

  1. package cn.demo;  
  2.   
  3. public class ZhangSan implements ISubscribe{  
  4.     private String mName;  
  5.     private String mNewsPaperName;  
  6.       
  7.     public ZhangSan(String mName, String mNewsPaperName) {  
  8.         this.mName = mName;  
  9.         this.mNewsPaperName = mNewsPaperName;  
  10.     }  
  11.       
  12.     public String getName() {  
  13.         return mName;  
  14.     }  
  15.   
  16.     public String getNewsPaperName() {  
  17.         return mNewsPaperName;  
  18.     }  
  19.       
  20.     @Override  
  21.     public void registered(PostOffice postOffice){  
  22.         postOffice.registeredNewsPaper(this);  
  23.     }  
  24.       
  25.     @Override  
  26.     public void unregistered(PostOffice postOffice){  
  27.         postOffice.unregisteredNewsPaper(this);  
  28.     }  
  29.   
  30.     @Override  
  31.     public void getNewsPaper() {  
  32.         // TODO Auto-generated method stub  
  33.         System.out.println("我是"+getName()+",我收到我订阅的"+getNewsPaperName());  
  34.     }  
  35.   
  36. }  

李四:

  1. package cn.demo;  
  2.   
  3. public class Lisi implements ISubscribe{  
  4.     private String mName;  
  5.     private String mNewsPaperName;  
  6.       
  7.     public Lisi(String mName, String mNewsPaperName) {  
  8.         this.mName = mName;  
  9.         this.mNewsPaperName = mNewsPaperName;  
  10.     }  
  11.       
  12.     public String getName() {  
  13.         return mName;  
  14.     }  
  15.   
  16.     public String getNewsPaperName() {  
  17.         return mNewsPaperName;  
  18.     }  
  19.       
  20.     @Override  
  21.     public void unregistered(PostOffice postOffice){  
  22.         postOffice.unregisteredNewsPaper(this);  
  23.     }  
  24.       
  25.     @Override  
  26.     public void registered(PostOffice postOffice){  
  27.         postOffice.registeredNewsPaper(this);  
  28.     }  
  29.   
  30.     @Override  
  31.     public void getNewsPaper() {  
  32.         // TODO Auto-generated method stub  
  33.         System.out.println("我是"+getName()+",我收到我订阅的"+getNewsPaperName());  
  34.     }  
  35.   
  36. }  

王五:

  1. package cn.demo;  
  2.   
  3. public class Wangwu implements ISubscribe{  
  4.     private String mName;  
  5.     private String mNewsPaperName;  
  6.       
  7.     public Wangwu(String mName, String mNewsPaperName) {  
  8.         this.mName = mName;  
  9.         this.mNewsPaperName = mNewsPaperName;  
  10.     }  
  11.       
  12.     public String getName() {  
  13.         return mName;  
  14.     }  
  15.   
  16.     public String getNewsPaperName() {  
  17.         return mNewsPaperName;  
  18.     }  
  19.       
  20.     @Override  
  21.     public void registered(PostOffice postOffice){  
  22.         postOffice.registeredNewsPaper(this);  
  23.     }  
  24.       
  25.     @Override  
  26.     public void unregistered(PostOffice postOffice){  
  27.         postOffice.unregisteredNewsPaper(this);  
  28.     }  
  29.   
  30.   
  31.     @Override  
  32.     public void getNewsPaper() {  
  33.         // TODO Auto-generated method stub  
  34.         System.out.println("我是"+getName()+",我收到我订阅的"+getNewsPaperName());  
  35.     }  
  36.   
  37. }  

三个订阅者,都有方法订阅报纸,或者取消订阅。其实关于订阅者的信息,是存储在邮局类里面。


邮局类:(邮局类应该继承一个抽象类或者接口(Subject),这里没有实现)

  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. public class PostOffice {  
  5.     private List<ISubscribe> SubscribeList = new ArrayList<ISubscribe>();  
  6.       
  7.     public void registeredNewsPaper(ISubscribe subscribe) {  
  8.         SubscribeList.add(subscribe);  
  9.     }  
  10.       
  11.     public void unregisteredNewsPaper(ISubscribe subscribe) {  
  12.         if (subscribe != null) {  
  13.             SubscribeList.remove(subscribe);  
  14.         }  
  15.           
  16.     }  
  17.       
  18.     public void getNewsPaper(boolean bool) {  
  19.         if (bool) {  
  20.             sendNewsPaper();  
  21.         }  
  22.     }  
  23.       
  24.     public void sendNewsPaper() {  
  25.         for(ISubscribe subscribe : SubscribeList) {  
  26.             subscribe.getNewsPaper();  
  27.         }  
  28.     }  
  29. }  
在这个类里面,有变化通知是使用的sendNewsPaper()这个方法,遍历所有的订阅者。
测试类:

  1. public static void main(String[] args) {  
  2.         // TODO Auto-generated method stub  
  3.         PostOffice mPostOffice = new PostOffice();  
  4.         ISubscribe zhangsan = new ZhangSan("张三""《南方周末》");  
  5.         ISubscribe lisi = new Lisi("李四""《新京报》");  
  6.         ISubscribe wangwu = new Wangwu("王五""《南方都市报》");  
  7.           
  8.         //开始订阅报纸  
  9.         zhangsan.registered(mPostOffice);  
  10.         lisi.registered(mPostOffice);  
  11.         wangwu.registered(mPostOffice);  
  12.           
  13.         //邮局收到报纸,开始发放  
  14.         mPostOffice.getNewsPaper(true);  
  15.           
  16.         //李四退订  
  17.         lisi.unregistered(mPostOffice);  
  18.         //邮局收到报纸,开始发放  
  19.         mPostOffice.getNewsPaper(true);  
  20.     }  

打印结果:

    

  1. 我是张三,我收到我订阅的《南方周末》  
  2. 我是李四,我收到我订阅的《新京报》  
  3. 我是王五,我收到我订阅的《南方都市报》  
  4. 我是张三,我收到我订阅的《南方周末》  
  5. 我是王五,我收到我订阅的《南方都市报》  

这里只是提供了一个简单的例子,而且代码你会发现有冗余,三个订阅者类,几乎是一样,因为没有在类里面添加他们独自的属性,可以用一个Person类来替代。这里写这三个类是为了显示清晰。

        关于五月18号的例子,观察者没必要有注册和取消注册的方法。他们的方法的实现也是调用的被观察者的注册和取消注册,不如直接使用被观察者的方法。

         在Android中,button.setOnclickListener()这个方式是比较常见的观察者模式:当然,众所周知,onClick是著名的回调方法,在这里不会研究回调,不用太在意。

看下代码:

  1. Button button1 = (Button)findViewById(R.id.button1);  
  2.         Button button2 = (Button)findViewById(R.id.button2);  
  3.         Button button3 = (Button)findViewById(R.id.button3);  
  4.         button1.setOnClickListener(this);  
  5.         button2.setOnClickListener(this);  
  6.         button3.setOnClickListener(this);  
  7.     }  
  8.   
  9.     @Override  
  10.     public void onClick(View v) {  
  11.         // TODO Auto-generated method stub  
  12.         switch(v.getId()) {  
  13.         case R.id.button1 :  
  14. //          do some thing         
  15.         case R.id.button2 :  
  16. //          do some thing  
  17.         case R.id.button3 :  
  18. //          do some thing  
  19.         }  
  20.     }  

先button.setOnclickListener()进行注册。相当于邮局中的lisi.registered(mPostOffice),此处错误,应该是第一例中的postOffice.registered(person)。onclick响应事件相当于邮局中的

  1. public void sendNewsPaper() {  
  2.         for(ISubscribe subscribe : SubscribeList) {  
  3.             subscribe.getNewsPaper();  
  4.         }  
  5.     }  

这个中的subscribe.getNewsPaper()这个方法。View.onClickListener相当于邮局。View也就是button是我们的订阅者,也就相当于张三。我们也可以在getNewsPaper中加一些自己的switch判断。

       最后,如果我们的邮局要实现类似button这样的回调这么实现呢?

  1. ISubscribe isubscribe;  
  2.   
  3.     @Override  
  4.     public void getNewsPaper() {  
  5.         // TODO Auto-generated method stub  
  6.         System.out.println("我是"+getName()+",我收到我订阅的"+getNewsPaperName());  
  7.         isubscribe.getNewsPaper();  
  8.     } 
目录
相关文章
|
20天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
20天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
23天前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
16天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
26 3
|
16天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
36 1
|
18天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
18天前
|
存储 搜索推荐 Java
打造个性化安卓应用:从设计到实现
【10月更文挑战第30天】在数字化时代,拥有一个个性化的安卓应用不仅能够提升用户体验,还能加强品牌识别度。本文将引导您了解如何从零开始设计和实现一个安卓应用,涵盖用户界面设计、功能开发和性能优化等关键环节。我们将以一个简单的记事本应用为例,展示如何通过Android Studio工具和Java语言实现基本功能,同时确保应用流畅运行。无论您是初学者还是希望提升现有技能的开发者,这篇文章都将为您提供宝贵的见解和实用的技巧。
|
22天前
|
搜索推荐 开发工具 Android开发
打造个性化Android应用:从设计到实现的旅程
【10月更文挑战第26天】在这个数字时代,拥有一个能够脱颖而出的移动应用是成功的关键。本文将引导您了解如何从概念化阶段出发,通过设计、开发直至发布,一步步构建一个既美观又实用的Android应用。我们将探讨用户体验(UX)设计的重要性,介绍Android开发的核心组件,并通过实际案例展示如何克服开发中的挑战。无论您是初学者还是有经验的开发者,这篇文章都将为您提供宝贵的见解和实用的技巧,帮助您在竞争激烈的应用市场中脱颖而出。
|
28天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
34 9
|
23天前
|
算法 Java 数据库
Android 应用的主线程在什么情况下会被阻塞?
【10月更文挑战第20天】为了避免主线程阻塞,我们需要合理地设计和优化应用的代码。将耗时操作移到后台线程执行,使用异步任务、线程池等技术来提高应用的并发处理能力。同时,要注意避免出现死循环、不合理的锁使用等问题。通过这些措施,可以确保主线程能够高效地运行,提供流畅的用户体验。
37 2

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    50
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    58
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    64
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    59
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    42
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    112
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78