其他分享
首页 > 其他分享> > 案例分析:设计模式与代码的结构特性

案例分析:设计模式与代码的结构特性

作者:互联网

模式存在的意义

现实生活中的例子

在现实世界中,很多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或多个其他对象的行为也发生改变。

例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心;还有,当我们开车到交叉路口时,遇到红灯会停,遇到绿灯会行。像这样的例子还有很多,比如股票价格与股民的联系、微信公众号与微信用户、气象局的天气预报与听众、小偷与警察等等。
在软件世界也是这样,例如,Excel 中的数据与折线图、饼状图、柱状图之间的关系;MVC 模式中的模型与视图的关系;事件模型中的事件源与事件处理者。

所有这些,如果用观察者模式来实现就非常方便。

观察者模式的动机

对于上述现实中存在的问题,观察者模式建立起一种对象与对象之间的依赖关系,当一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。
在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。

观察者模式的定义与结构

模式的定义

观察者(Observer)模式是指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

因此这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

观察者模式是一种对象行为型模式,其主要优点在于:

模式的结构

观察者模式所包含的主要角色有:
1.抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法;
2.具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象;
3.抽象观察者(Observer)角色:它是一个抽象类或接口,包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用;
4.具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

Obesever

观察者模式的应用实例

本文将利用观察者模式设计一个学校铃声的事件处理程序。

问题分析

在本实例中,学校的“铃”是事件源和目标,“老师”和“学生”是事件监听器和具体观察者,“铃声”是事件类。
学生和老师来到学校的教学区,都会注意学校的铃,这叫事件绑定
当上课时间或下课时间到,会触发铃发声,这时会生成“铃声”事件
学生和老师听到铃声会开始上课或下课,这叫事件处理

这个实例非常适合用观察者模式实现,下图给出了学校铃声的事件模型。
Ling

应用观察者模式的思路

现在用观察者模式来实现该事件处理模型。实现步骤分为以下四步:

按照以上的实现思路,可以得出下图的学校铃声事件处理程序的结构。
学校铃声事件处理程序的结构

代码实现

铃声事件类:用于封装事件源及一些与事件相关的参数

public class RingEvent extends EventObject
{   
    private static final long serialVersionUID=1L;
    private boolean sound;    //true表示上课铃声,false表示下课铃声
    public RingEvent(Object source,boolean sound)
    {
        super(source);
        this.sound=sound;
    }   
    public void setSound(boolean sound)
    {
        this.sound=sound;
    }
    public boolean getSound()
    {
        return this.sound;
    }
}

抽象观察者类:铃声事件监听器

public interface  BellEventListener extends EventListener
{
    //事件处理方法,听到铃声
    public void heardBell(RingEvent e);
}

目标类:事件源,学校的铃

public class BellEventSource {
    private List<BellEventListener> listener; //监听器容器
    public BellEventSource()
    {
        listener=new ArrayList<BellEventListener>();
    }
    //给事件源绑定监听器
    public void addPersonListener(BellEventListener ren)
    {
        listener.add(ren);
    }
    //事件触发器:敲钟,当铃声sound的值发生变化时,触发事件。
    public void ring(boolean sound)
    {
        String type=sound?"上课铃":"下课铃";
        System.out.println(type+"响!");
        RingEvent event=new RingEvent(this, sound);
        notifies(event);    //通知注册在该事件源上的所有监听器
    }
    //当事件发生时,通知绑定在该事件源上的所有监听器做出反应(调用事件处理方法)
    protected void notifies(RingEvent e)
    {
        BellEventListener ren=null;
        Iterator<BellEventListener> iterator=listener.iterator();
        while(iterator.hasNext())
        {
            ren=iterator.next();
            ren.heardBell(e);
        }
    }

}

具体观察者类:老师事件监听器

public class TeachEventListener implements BellEventListener
{
    public void heardBell(RingEvent e)
    {
        if(e.getSound())
        {
            System.out.println("老师上课了...");
        }
        else
        {
            System.out.println("老师下课了...");
        }
    }
}

具体观察者类:学生事件监听器

public class StuEventListener implements BellEventListener
{
    public void heardBell(RingEvent e)
    {
        if(e.getSound())
        {
            System.out.println("同学们,上课了...");
        }
        else
        {
            System.out.println("同学们,下课了...");
        }
    }
}

测试类

public class Test
{
    public static void main(String[] args)
    {
        BellEventSource bell=new BellEventSource();    //铃(事件源)
        bell.addPersonListener(new TeachEventListener()); //注册监听器(老师)
        bell.addPersonListener(new StuEventListener());    //注册监听器(学生)
        bell.ring(true);   //打上课铃声
        System.out.println("====================");
        bell.ring(false);  //打下课铃声
    }
}

实例总结

引入该设计模式后对系统架构和代码结构带来了哪些好处

代码实现用到的多态机制

在本实例中,所用到的多态机制较为明显。
比如具体观察者类的学生事件监听器以及老师事件监听器就是在实现抽象观察者类:铃声事件监听器的基础上完成的。

接口的多种不同的实现方式即为多态

观察者模式总结

模式的适用场景

观察者模式的优缺点

优点

缺点

参考链接

Graphic Design Patterns
观察者模式的优点和缺点
观察者模式(Observer模式)详解

标签:铃声,对象,代码,观察者,模式,案例,监听器,设计模式,public
来源: https://www.cnblogs.com/RichardTAO/p/11988976.html