繁体   English   中英

立面图案结合观察者模式

[英]Facade pattern combined with observer pattern

我得到了一个任务,以确切了解外观模式是什么。 我用Google搜索并发现它是为了通过制作“界面”来保护客户端免受非常复杂的系统的攻击。 所以,我有几个问题,我已经在多个例子看到的是他们为复杂系统的C#接口,但我也看到,使用的类的“接口”少数(如看到这里 )。 我只能理解它,如果它是一个基类,简化了很多不同类的复杂方法调用,如(在这里看到的银行示例)

  1. 所以我的第一个问题是,如果我是正确的,你将把“接口”作为一个类来实现?

  2. 我的另一个问题是,你可以将外观模式与观察者模式一起使用。 Facade类将观察所有主题,然后根据主题控制不同类中应该调用哪些方法?


编辑:作为requsted,我试图用一个观察者模式的外观做一个示例项目,结果如下:

public class Facade
{

    private Dictionary<ISubject, List<IObserver>> Subjects { get; set; }

    public Facade()
    {
        Subjects = new Dictionary<ISubject, List<IObserver>>();
    }

    public void AddObserverToSubject(ISubject sub,IObserver obs)
    {
        if (Subjects.ContainsKey(sub))
            Subjects[sub].Add(obs);
        else
        {
            List<IObserver> observers = new List<IObserver>();
            observers.Add(obs);
            Subjects.Add(sub, observers);
        }
        obs.Subject = sub;
    }

    public void DeleteObserverFromSubject(IObserver obs,ISubject subject)
    {
        Subjects[subject].Remove(obs);
    }
    public void Notify(ISubject subject)
    {
        foreach (var observer in Subjects[subject])
        {
            observer.Update();
        }

    }
}

public interface ISubject
{
    Facade Observers { get; set; }
    int GetState();
    void SetState(int state);
}

public interface IObserver
{
    ISubject Subject { get; set; }
    void Update();
    string Mood { get; }
}

因此,每个观察者都会根据主题的内容更新自己的情绪。

我已经做了两个IObserver和ISubject的实现,但我只会在这里展示其中一个。

public class TeacherObserver : IObserver
{
    public ISubject Subject { get; set; }
    private int _currentSalery = 500;
    public string Mood { get; private set; }
    public TeacherObserver()
    {
        Mood = "Happy";
    }


    public void Update()
    {
        var newSalery = Subject.GetState();
        if (_currentSalery < newSalery)
        {
            Mood = "Happy";
        }
        else
        {
            Mood = "Sad";
        }
        _currentSalery = newSalery;
    }
}

public class SalerySubject :ISubject
{
    public Facade Observers { get; set; }
    private int _salery;
    public int GetState()
    {
        return _salery;
    }

    public void SetState(int state)
    {
        _salery = state;
        Observers.Notify(this);
    }
}

所以我喜欢这个的一件事是主题不必知道绑定它的所有观察者(现在将由facade类处理)。 但是从客户的角度来看,这与他必须做的几乎相同:

class Program
{
    static void Main(string[] args)
    {
        Facade.Facade observer = new Facade.Facade();
        ISubject salery = new SalerySubject();
        IObserver teacher = new TeacherObserver();
        salery.Observers = observer;
        observer.AddObserverToSubject(salery,teacher);
        Console.WriteLine("Teacher is " + teacher.Mood);
        salery.SetState(100);
        Console.WriteLine("Teacher salery just went down. The teacher is now " + teacher.Mood);
    }
}
  1. 这让我觉得用门面做这件事真的没有意义,因为门面的重点是让客户更容易吗? (或隐藏信息)或我错了?

我得到了一个任务,以确切了解外观模式是什么

Facade只是另一个包装。
它包装了一些实体,通常是为了隐藏客户端的一些细节。

如果我是正确的,你会把“接口”作为一个类来实现?

接口是合同。

要实现这个合同,你需要一个类(因为我们谈论的是设计模式,我省略了结构讨论)。 换句话说,您不能仅使用接口来实现 Facade,因为您需要一个类,其中将放置实现逻辑,但是接口可以帮助您使组件松散耦合。

实际上,使用界面或不使用界面与特定模式无关。

你可以将立面图案与观察者图案一起使用吗?

理论上 - 是的,你可以。 在实践中 - 这取决于。

我认为术语“界面”的用法不同。 你有一个“接口东西”的通用术语来访问它,你有一个具体的术语'c#接口定义'作为该语言的一部分。 所以我认为,在你的报价中

通过制作“界面”来保护客户端免受非常复杂的系统的影响

使用了第一个通用含义。 问题是如何构建它:

1.所以我的第一个问题是,如果我是正确的,你会把“接口”作为一个类来实现吗?

我会两个都用。 首先,我将创建一个c#接口来定义契约,然后构建一个基类作为参考实现。 如果你只使用一个基类,那么所有其他可能的类都必须继承这个,他们只得到实现细节,因为他们想要合同。 如果其他可能的类可以使用您的接口,则只需要实现它,这意味着它们必须在接口定义中提供方法并且彼此之间没有链接。

那么我的另一个问题是,你能否使用立面图案和观察者模式。 Facade类将观察所有主题,然后根据主题控制不同类中应该调用哪些方法?

是的,你可以,但随后所有类的观察行为都是立面的“一部分”。 如果那就是你想要的,好吧。

3.这导致我认为用立面来做它真的没有意义,因为立面的整个要点是让客户更容易吗? (或隐藏信息)或我错了?

我认为为其定义的目的设置一个外观是有意义的,以便连接它背后的复杂系统。 只有当观察行为没有任何内容时,才有隐藏的复杂性。

所以我可以建议像这样重新设计:

我会用一个事件实现ISubject ,因为它不需要知道谁在观察,它只会通知:

public interface ISubject
{
    event EventHandler OnNotify;
}

然后创建第二个接口以提供对薪水的访问权限:

public interface ISalerySubject: ISubject
{
    int Salery { get; set; }
}

IObserver可以容纳一个ISubject

public interface IObserver
{
    ISubject Subject { get; set; }
}

现在让我们具体化吧。 SalerySubject是实现接口ISalerySubject ,所以当salery改变时,触发事件:

public class SalerySubject : ISalerySubject
{
    public event EventHandler OnNotify;

    private int salery;
    public int Salery
    {
        get { return salery; }
        set
        {
            salery = value;
            if (OnNotify != null) OnNotify(this, new EventArgs());
        }
    }

}

TeacherObserver类正在实现接口IObserver ,它将它的方法Update绑定到ISubject的事件:

public class TeacherObserver : IObserver
{
    private int _currentSalery = 500;
    public string Mood { get; private set; }

    public ISubject subject;
    public ISubject Subject
    {
        get { return subject; } 
        set
        {
            // Relase old event
            if (subject != null) subject.OnNotify -= Update;

            subject = value;

            // Connect new event
            if (subject != null) subject.OnNotify += Update;
        } 
    }

    public TeacherObserver()
    {
        Mood = "Happy";
    }


    public void Update(object sender, EventArgs e)
    {
        ISalerySubject SalerySubject = Subject as ISalerySubject;
        if (SalerySubject != null)
        {
            var newSalery = SalerySubject.Salery;
            if (_currentSalery < newSalery)
            {
                Mood = "Happy";
            }
            else
            {
                Mood = "Sad";
            }
            _currentSalery = newSalery;
        }
    }
}

现在你可以使用它:

class Program
{
    static void Main(string[] args)
    {
        ISalerySubject salery = new SalerySubject();
        TeacherObserver teacher = new TeacherObserver();
        teacher.Subject = salery;

        Console.WriteLine("Teacher is " + teacher.Mood);
        salery.Salery = 100 ;
        Console.WriteLine("Teacher salery just went down. The teacher is now " + teacher.Mood);
    }
}   

所以,到目前为止,不需要外立面。 也许你想保留一个观察者列表,但通常不存储在一个外观中。 也许你的系统要复杂得多,所以无论如何都有一个很好的理由。

立面图案是结构设计图案。 https://sourcemaking.com/design_patterns/facade

外观用于将应用程序(或模型)的基础逻辑与用户界面分开。 它的目的是分离关注点并帮助简化底层类结构的使用。

façade本身是一个抽象类,它列出了可以为该接口实现的方法以及这些方法如何连接到模型的底层类结构。 具体实现是底层模型类的实际创建,对象以及使用这些对象实例来运行程序。 一直以来,底层程序逻辑的过程只通过外观调用,并且与最终用户无关。

在此输入图像描述

观察者模式是行为设计​​模式。 https://sourcemaking.com/design_patterns/observer

观察者模式链接一个对象及其所有依赖项。 因此,当对象发生任何更改时,所有链接的依赖项也将受此更改的影响。 它是MVC应用程序中使用的模式之一。 模型/对象维护所有业务逻辑; 这被传递给控制器​​/观察者。 然后,控制器根据用户对对象所做的更改来更新和维护视图。

控制器/观察者将编程逻辑的关注点与用户分开,就像外观将其与用户分开一样。 控制器/观察者与模型和视图是不可分离的。 它依赖于对两者的访问来充当两者之间的外行解释器,将模型逻辑解析为用户界面,反之亦然。

在此输入图像描述


说实话,我没有很好地跟着你。 我认为你将收藏的想法与设计模式混为一谈。

在我看来,混合两者的逻辑将混淆使用任一模式背后的编程逻辑。 虽然设计模式可能不是很明确,但这是一个特殊的例子,我不能(在我的头脑中)想到一个有用的应用程序。 如果有有用的例子,我相信有人会说清楚。

是的,我同意您对外观的理解 - Facade的目的是为复杂系统提供新的简化界面(或接入点或网关)。 或者是统一的界面来隐藏多个子系统。

现在,我将逐一回答您的问题 -

所以我的第一个问题是,如果我是正确的,你将把“接口”作为一个类来实现?

当我们在立面的上下文中使用“接口”时,它指的是API ,传达了 - 交互 接触 点的含义。 外观充当客户端和复杂系统之间的联系点

现在,如何实现立面? 当然,您可以使用c# interface来定义Facade将向客户端公开的函数,事件和属性。 实际的包装器将是一个实现此interfaceclass

即使您隐藏的复杂系统是静态的,在实现interfaceclass包装静态系统,在实现单元测试时也会有所帮助。

我的另一个问题是,你可以将外观模式与观察者模式一起使用。 Facade类将观察所有主题,然后根据主题控制不同类中应该调用哪些方法?

从语言纯度的角度来看,外观应该只在包装的子系统的现有API上定义新的API。

如果您隐藏系统需要发布者 - 订阅者模型,则必须在外观中实现观察者模式,包装子系统的发布者 - 订阅者调用。

但是,不要以简单的名义为门面添加更多的职责或逻辑,将其视为子系统的相当简单的倡导者或推动者,仅此而已。 它不应该成为一个无所不知的“上帝”对象。

这让我觉得用门面做这件事真的没有意义,因为门面的重点是让客户更容易吗? (或隐藏信息)或我错了?

在您的示例中,所有这些逻辑都不应该在外观中。 我同意它会让客户更容易,但它不是建立在包装的子系统上,而是像门面提供的附加服务。 因此,从外观进入一个单独的类,客户端可以使用该类来使其生活轻松。

如果您认为外立面中有任何东西可以从外立面中取出而不暴露子系统,则必须将该外观取出。

希望能帮助到你。 如果有任何不清楚或者你认为我错过了你的任何问题我们可以从那里拿走它,请给我写评论。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM