澳门威利斯人_威利斯人娱乐「手机版」

来自 办公软件 2020-02-03 08:02 的文章
当前位置: 澳门威利斯人 > 办公软件 > 正文

观察者模式,设计模式之观察者模式

五个系统在顾客登陆的时候,平日要记录一些事物:session、登六次数、总计在线时间长度等;假如这么多的操作遵照面向进程的方法编写,使二个指标变得复杂,它要操作这么多的作业,那样也违反单生机勃勃作用原则。

何以是观望者格局?

图片 1
观望者方式定义了蓬蓬勃勃种后生可畏对多的依据关系,让八个观看者对象同有的时候间监听某八个主旨对象,那么些核心对象在情景产生变化时,会打招呼全数观望者对象,使它们能够自动更新自身的行为。
结构:
图片 2
能够看看,在观看者方式的构造图有以下角色:

  • 泛泛主旨剧中人物(Subject):抽象核心把具有观望者对象的援用保存在七个列表中,并提供增删观望者对象的操作,抽象大旨剧中人物又称之为抽象被观察者剧中人物,日常由抽象类或接口达成。
  • 空洞观望者角色(Observer):为保有具体观望者定义贰个接口,在拿到大旨文告时更新自身,平时由抽象类或接口实现。
  • 切切实实宗旨角色(ConcreteSubject):完毕抽象大旨接口,具体大旨剧中人物又称为具体被观望者角色。
  • 切切实实观望者角色(ConcreteObserver):达成抽象观看者剧中人物所必要的接口,以便使笔者状态与宗旨的图景相调养。

若果那个操作以插件方式加载或移除,那么登六只完结它的纯粹功用操作。

设计深入分析及代码实现

大家以监察QQ游戏群众号的音讯推送为例展开商讨。

First:

namespace DesignPattern.Observer.First
{
    /// <summary>
    /// QQ游戏公众号
    /// </summary>
    public class QQGame
    {
        /// <summary>
        /// 订阅对象
        /// </summary>
        public Subscriber Subscriber { get; set; }

        public string Symbol { get; set; }

        public string Info { get; set; }

        public QQGame(string symbol,string info)
        {
            this.Symbol = symbol;
            this.Info = info;
        }

        public void Update()
        {
            if (Subscriber!=null)
            {
                Subscriber.ReceiveAndPrintData(this);
            }
        }
    }
}

namespace DesignPattern.Observer.First
{
    /// <summary>
    /// 订阅者类
    /// </summary>
    public class Subscriber
    {
        public string Name { get; set; }

        public Subscriber(string name)
        {
            this.Name = name;
        }

        public void ReceiveAndPrintData(QQGame game)
        {
            Console.WriteLine("Notified {0} of {1}'s"   " Info is: {2}", Name, game.Symbol, game.Info);
        }
    }
}

class Program
{
    /// <summary>
    /// 调用
    /// </summary>
    /// <param name="args"></param>
    static void Main(string[] args)
    {
        // 第一种方式
        Observer.First.Subscriber XiaoMingSub = new Observer.First.Subscriber("XiaoMing");
        Observer.First.QQGame qqGame1 = new Observer.First.QQGame("QQ Game", "Have a new game published ....");
        qqGame1.Subscriber = XiaoMingSub;
        qqGame1.Update();

        Console.ReadLine();
    }
}

上面代码确实完结了督查订阅号的天职。但此处的落到实处存在下边多少个难题:

  • QQGame类和Subscriber类之间产生了意气风发种双向注重关系,三个类变化将唤起另七个类的改观。
  • 当现身二个新的订阅者时,那时必须要改过QQGame代码,即增多另二个订阅者的援用和在Update方法中调用另叁个订阅者的办法。

Next:
这么的安顿性违背了“开放——密闭”原则,鲜明不是我们想要的。下边做出改正:

  • 订阅者抽象出贰个接口,用它来撤消QQGame类与实际的订阅者之间的信任性
  • QQGame中运用一个列表来保存全部的订阅者对象,内部再增加对该列表的操作

兑今世码为:

namespace DesignPattern.Observer.Next
{
    public abstract class AbstractGame
    {
        // 订阅者列表
        private List<IObserver> observers = new List<IObserver>();

        public string Symbol { get; set; }

        public string Info { get; set; }

        public AbstractGame(string symbol, string info)
        {
            this.Symbol = symbol;
            this.Info = info;
        }

        public void AddObserver(IObserver ob)
        {
            observers.Add(ob);
        }

        public void RemoveObserver(IObserver ob)
        {
            observers.Remove(ob);
        }

        public void Update()
        {
            foreach (var ob in observers)
            {
                if (ob != null)
                {
                    ob.ReceiveAndPrint(this);
                }
            }
        }
    }
}

namespace DesignPattern.Observer.Next
{
    public class QQGame : AbstractGame
    {
        public QQGame(string symbol, string info)
            : base(symbol, info)
        {
        }
    }
}

namespace DesignPattern.Observer.Next
{
    public interface IObserver
    {
        void ReceiveAndPrint(AbstractGame game);
    }
}

namespace DesignPattern.Observer.Next
{
    public class Subscriber : IObserver
    {
        public string Name { get; set; }

        public Subscriber(string name)
        {
            this.Name = name;
        }

        public void ReceiveAndPrint(AbstractGame game)
        {
            Console.WriteLine("Notified {0} of {1}'s"   " Info is: {2}", Name, game.Symbol, game.Info);
        }
    }
}

class Program
{
    /// <summary>
    /// 调用
    /// </summary>
    /// <param name="args"></param>
    static void Main(string[] args)
    {
        // 第二种方式
        Observer.Next.QQGame qqGame2 = new Observer.Next.QQGame("QQ Game", "Have a new game published ....");
        qqGame2.AddObserver(new Observer.Next.Subscriber("XiaoMing"));
        qqGame2.Update();

        Console.ReadLine();
    }
}

如此的落成便是阅览者情势的兑现。在此外时候,只要调用了AbstractGame类的Update方法,它就能够通报全体的观望者对象,相同的时候,撤销了直白注重,变为直接信任,这样大大提供了系统的可维护性和可扩展性。

Last:
行使委托与事件来简化观望者形式的得以完成

namespace DesignPattern.Observer.Last
{
    public abstract class AbstractGame
    {
        // 委托充当订阅者接口类
        public delegate void NotifyEventHandler(object sender);

        public NotifyEventHandler NotifyEvent;

        public string Symbol { get; set; }

        public string Info { get; set; }

        public AbstractGame(string symbol, string info)
        {
            this.Symbol = symbol;
            this.Info = info;
        }

        public void AddObserver(NotifyEventHandler ob)
        {
            NotifyEvent  = ob;
        }

        public void RemoveObserver(NotifyEventHandler ob)
        {
            NotifyEvent -= ob;
        }

        public void Update()
        {
            if (NotifyEvent != null)
            {
                NotifyEvent(this);
            }
        }
    }
}

namespace DesignPattern.Observer.Last
{
    public class QQGame : AbstractGame
    {
        public QQGame(string symbol, string info)
            : base(symbol, info)
        {
        }
    }
}

namespace DesignPattern.Observer.Last
{
    public class Subscriber
    {
        public string Name { get; set; }

        public Subscriber(string name)
        {
            this.Name = name;
        }

        public void ReceiveAndPrint(Object obj)
        {
            AbstractGame game = obj as AbstractGame;
            if (game != null)
            {
                Console.WriteLine("Notified {0} of {1}'s"   " Info is: {2}", Name, game.Symbol, game.Info);
            }
        }
    }
}

class Program
{
    /// <summary>
    /// 调用
    /// </summary>
    /// <param name="args"></param>
    static void Main(string[] args)
    {
        // 第三种方式
        Observer.Last.QQGame qqGame3 = new Observer.Last.QQGame("QQ Game", "Have a new game published ....");
        var xiaoming = new Observer.Last.Subscriber("XiaoMing");
        var xiaohong = new Observer.Last.Subscriber("XiaoHong");

        qqGame3.AddObserver(new Observer.Last.AbstractGame.NotifyEventHandler(xiaoming.ReceiveAndPrint));
        qqGame3.AddObserver(new Observer.Last.AbstractGame.NotifyEventHandler(xiaohong.ReceiveAndPrint));

        qqGame3.Update();

        Console.ReadLine();
    }
}

应用事件和嘱托完毕的观看者方式中,收缩了订阅者接口类的定义,那个时候,.委托正式出任订阅者接口类的剧中人物。

  • 如此那般就足以接收阅览者形式,早先时期再充实相关功用模块,不供给太多干活儿就足以加载同步;也不用改进登陆的作用;
  • 缺欠就是因为各种插件模块分散,前边功效也许重叠此前的遵守,引致数据失实,所以在应用时要硬着头皮注释只怕整理好文书档案

观望者情势的利害

优点:

  • 观望者情势完成了表示层和数码逻辑层的分开,并定义了和谐的改过音讯传递机制,并抽象了履新接口,使得能够有各式各样分歧的表示层,即观望者。
  • 观看者方式在被观望者和观看者之间确立了三个硕华而不实的耦合,被观望者并不知道任何贰个实际的观察者,只是保存着抽象观看者的列表,每一个具体观看者都合乎一个架空阅览者的接口。
  • 观看者方式扶植广播通讯。被观察者会向具备的注册过的观望者发出公告。

缺点:

  • 设若贰个被观察者有广大直接和直接的观望者时,将有所的观望者都通报插足费用超多时日。
  • 即使观望者情势能够任何时候使观看者知道所寓指标指标发送了转移,但是旁观者形式尚未对景挂画的机制使阅览者知道所观看的指标是怎么发生变化的。
  • 假若在被观察者之间有轮回信任的话,被观望者会触发它们中间开展巡回调用,招致系统崩溃,在接收观望者格局应非常注意那一点。

观望者情势的适用项景

以下情形能够思索接纳观察者格局:

  • 当一个虚幻模型有多少个方面,此中二个地点正视于另一个地方,将这两头封装在单独的对象中以使它们得以独家独立地转移和复用的情形下。
  • 当对贰个对象的更动须要同有的时候间改进别的对象,而又不晓得具体某个许对象有待改换的气象下。
  • 当二个目的必需通报任何对象,而又不能够假定其余对象是何人的景况下。

代码

  • 当一个硕大而无当模型有五个方面,个中三个方面信任于另叁个方面。
  • 当对一个目的的转移须求同期改造此外对象,而不明了具体有多少个目的待改正。
  • 当一个目的必须通报任何对象,而它又不可能假定其它对象是什么人。换句话说,你不期待那个目的是密不可分耦合的

php已经提供了主题接口类和观看者接口类,还应该有二个SplObjectStorage数据布局对象容器——完毕了Countable,Iterator,Serializable,ArrayAccess四个接口。可达成计算、迭代、类别化、数组式访谈等功能。

  • 主题类
namespace Observer;use SplObjectStorage;use SplObserver;use SplSubject;class User implements SplSubject{ /** * @var SplObjectStorage */ private $observers; public function __construct() { $this->observers = new SplObjectStorage(); } /** * Attach an SplObserver * @link http://php.net/manual/en/splsubject.attach.php * @param SplObserver $observer <p> * The <b>SplObserver</b> to attach. * </p> * @return void * @since 5.1.0 */ public function attach(SplObserver $observer) { $this->observers->attach($observer); } /** * Detach an observer * @link http://php.net/manual/en/splsubject.detach.php * @param SplObserver $observer <p> * The <b>SplObserver</b> to detach. * </p> * @return void * @since 5.1.0 */ public function detach(SplObserver $observer) { $this->observers->detach($observer); } /** * Notify an observer * @link http://php.net/manual/en/splsubject.notify.php * @return void * @since 5.1.0 */ public function notify() { foreach ($this->observers as $observer) { $observer->update; } }}

本文由澳门威利斯人发布于办公软件,转载请注明出处:观察者模式,设计模式之观察者模式

关键词: 澳门威利斯人 设计模式 PHP 模式 观察者