简体   繁体   English

立面图案结合观察者模式

[英]Facade pattern combined with observer pattern

I got an assignment to find out exactly what the facade pattern is. 我得到了一个任务,以确切了解外观模式是什么。 I have googled and found out it is meant to shield a client from a very complex system by making an "interface". 我用Google搜索并发现它是为了通过制作“界面”来保护客户端免受非常复杂的系统的攻击。 So I have a few questions, I have seen in multiple examples is they make an C# interface for the complex system, but I have also seen a few that used A class as the "Interface" (as seen here ). 所以,我有几个问题,我已经在多个例子看到的是他们为复杂系统的C#接口,但我也看到,使用的类的“接口”少数(如看到这里 )。 I can only make sense of it if it is a base class that simplifies a lot of different complex method calls to different classes as in (the bank example seen here ) 我只能理解它,如果它是一个基类,简化了很多不同类的复杂方法调用,如(在这里看到的银行示例)

  1. So my first question is if I am correct that you would implement the "interface" as a class? 所以我的第一个问题是,如果我是正确的,你将把“接口”作为一个类来实现?

  2. My other question then is, could you use facade pattern together with the observer pattern. 我的另一个问题是,你可以将外观模式与观察者模式一起使用。 The facade class would observe on all subjects and then control what methods in different classes should be called, depending on the subject? Facade类将观察所有主题,然后根据主题控制不同类中应该调用哪些方法?


Edit: As requsted I tried to make an example project with a facade for a observer pattern and here is the result: 编辑:作为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; }
}

So every observer will update their mood depending on what is going on with the subject. 因此,每个观察者都会根据主题的内容更新自己的情绪。

I have made two implementations of IObserver and ISubject but I will only show one of each here. 我已经做了两个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);
    }
}

So one thing I like about this is that the subject doesn't have to know about all the observers that is bound to it(this will be handled by the facade class now). 所以我喜欢这个的一件事是主题不必知道绑定它的所有观察者(现在将由facade类处理)。 But seeing from the clients view it is pretty much the same calls he would have to make: 但是从客户的角度来看,这与他必须做的几乎相同:

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. Which leads me to thinking that it doesn't really make sense to do it with a facade, as the whole point of the facade is to make it easier for the client right? 这让我觉得用门面做这件事真的没有意义,因为门面的重点是让客户更容易吗? (or hide information) or am I wrong? (或隐藏信息)或我错了?

I got an assignment to find out exactly what the facade pattern is 我得到了一个任务,以确切了解外观模式是什么

Facade is just yet another wrapper. Facade只是另一个包装。
It wraps some entity, usually to hide some details from client. 它包装了一些实体,通常是为了隐藏客户端的一些细节。

if I am correct that you would implement the "interface" as a class? 如果我是正确的,你会把“接口”作为一个类来实现?

Interface is a contract. 接口是合同。

To implement this contract, you need a class (since we're talking about design patterns, I'm omitting structures discussion). 要实现这个合同,你需要一个类(因为我们谈论的是设计模式,我省略了结构讨论)。 In other words, you can't implement facade using interface only, because you need a class, where implementation logic will be placed, but interface could help you to make your components loosely coupled. 换句话说,您不能仅使用接口来实现 Facade,因为您需要一个类,其中将放置实现逻辑,但是接口可以帮助您使组件松散耦合。

Actually, to use interface or not to use is unrelated to particular pattern. 实际上,使用界面或不使用界面与特定模式无关。

could you use facade pattern together with the observer pattern 你可以将立面图案与观察者图案一起使用吗?

In theory - yes, you can. 理论上 - 是的,你可以。 In practice - it depends. 在实践中 - 这取决于。

I think the term 'interface' is used in different meanings. 我认为术语“界面”的用法不同。 You have the general term of 'interface for something' to access it and you have the concret term 'c# interface definition' as part of that language. 你有一个“接口东西”的通用术语来访问它,你有一个具体的术语'c#接口定义'作为该语言的一部分。 So i think, in your quote 所以我认为,在你的报价中

to shield a client from a very complex system by making an "interface" 通过制作“界面”来保护客户端免受非常复杂的系统的影响

the first general meaning is used. 使用了第一个通用含义。 And the question is how to build it: 问题是如何构建它:

1.So my first question is if I am correct that you would implement the "interface" as a class? 1.所以我的第一个问题是,如果我是正确的,你会把“接口”作为一个类来实现吗?

I would use both. 我会两个都用。 First, i would create an c# interface to define the contract, then build a base class as reference implementation. 首先,我将创建一个c#接口来定义契约,然后构建一个基类作为参考实现。 If you use only a base class, then all other possible classes have to inherit from this and they get the implementation details only because they wanted the contract. 如果你只使用一个基类,那么所有其他可能的类都必须继承这个,他们只得到实现细节,因为他们想要合同。 If the other possible classes can use your interface, they only have to implement it, that means they have to provide the methods in the interface definition and have no link to each other. 如果其他可能的类可以使用您的接口,则只需要实现它,这意味着它们必须在接口定义中提供方法并且彼此之间没有链接。

2.My other question then is, could you use facade pattern together with the observer pattern. 那么我的另一个问题是,你能否使用立面图案和观察者模式。 The facade class would observe on all subjects and then control what methods in different classes should be called, depending on the subject? Facade类将观察所有主题,然后根据主题控制不同类中应该调用哪些方法?

Yes you can, but then the observing behaviour with all it's classes is 'part' of the facade. 是的,你可以,但随后所有类的观察行为都是立面的“一部分”。 If that is what you want, ok. 如果那就是你想要的,好吧。

3.Which leads me to thinking that it doesn't really make sense to do it with a facade, as the whole point of the facade is to make it easier for the client right? 3.这导致我认为用立面来做它真的没有意义,因为立面的整个要点是让客户更容易吗? (or hide information) or am I wrong? (或隐藏信息)或我错了?

I think it does make sense to have a facade for the purpose it is defined for, to interface the complex system behind it. 我认为为其定义的目的设置一个外观是有意义的,以便连接它背后的复杂系统。 Only if there is nothing then the observing behaviour, then there is no complexity to hide. 只有当观察行为没有任何内容时,才有隐藏的复杂性。

So may i suggest a little redesign like this: 所以我可以建议像这样重新设计:

I would implement ISubject with an event, because it doesn't need to know who is observing, it will simply notify: 我会用一个事件实现ISubject ,因为它不需要知道谁在观察,它只会通知:

public interface ISubject
{
    event EventHandler OnNotify;
}

and then create a second interface to give access to a salary: 然后创建第二个接口以提供对薪水的访问权限:

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

The IObserver can hold a ISubject : IObserver可以容纳一个ISubject

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

Now lets get concrete. 现在让我们具体化吧。 The class SalerySubject is implementing the interface ISalerySubject , so when the salery is changed the event is fired: 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());
        }
    }

}

The class TeacherObserver is implementing the interface IObserver and it binds it's method Update to the event of ISubject : 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;
        }
    }
}

Now you can use it: 现在你可以使用它:

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);
    }
}   

So, up to this point, there is no need for a facade. 所以,到目前为止,不需要外立面。 Maybe you want to keep a list of observers, but that normally is not stored in a facade. 也许你想保留一个观察者列表,但通常不存储在一个外观中。 Maybe your system is far more complex, so then there is a good reason for a facade anyway. 也许你的系统要复杂得多,所以无论如何都有一个很好的理由。

The façade pattern is a structural design pattern. 立面图案是结构设计图案。 https://sourcemaking.com/design_patterns/facade https://sourcemaking.com/design_patterns/facade

The façade acts to separate the underlying logic of an app (or model) from the user interface. 外观用于将应用程序(或模型)的基础逻辑与用户界面分开。 It serves the purpose of separating concerns and assists in simplifying the use of the underlying class structures. 它的目的是分离关注点并帮助简化底层类结构的使用。

The façade itself is an abstract class that sets out the methods that can be implemented for that interface and how these methods connect to the underlying class structures of the model. façade本身是一个抽象类,它列出了可以为该接口实现的方法以及这些方法如何连接到模型的底层类结构。 The concrete implementation is the actual creation of the underlying model classes, into objects and using these object instances to run the program. 具体实现是底层模型类的实际创建,对象以及使用这些对象实例来运行程序。 All the while the processes of the underlying program logic is only called through the façade and is of no concern to the end user. 一直以来,底层程序逻辑的过程只通过外观调用,并且与最终用户无关。

在此输入图像描述

The observer pattern is a behavioural design pattern. 观察者模式是行为设计​​模式。 https://sourcemaking.com/design_patterns/observer https://sourcemaking.com/design_patterns/observer

The observer pattern links an object with all its dependencies. 观察者模式链接一个对象及其所有依赖项。 So when any change in the object is made, all the linked dependencies will also be affected by this change. 因此,当对象发生任何更改时,所有链接的依赖项也将受此更改的影响。 It is one of the pattern used in MVC applications. 它是MVC应用程序中使用的模式之一。 The model/object maintains all the business logic; 模型/对象维护所有业务逻辑; this is passed to the controller/observer. 这被传递给控制器​​/观察者。 The controller then updates and maintains the views based on changes made by the user to the object. 然后,控制器根据用户对对象所做的更改来更新和维护视图。

The controller/observer separates the concerns, of the programming logic from the user, much as the façade separates it from the user. 控制器/观察者将编程逻辑的关注点与用户分开,就像外观将其与用户分开一样。 The controller/observer is inseparable from the model and view. 控制器/观察者与模型和视图是不可分离的。 It is reliant upon access to both to act as a layman's interpreter between the two, parsing the model logic into the user interface and vice versa. 它依赖于对两者的访问来充当两者之间的外行解释器,将模型逻辑解析为用户界面,反之亦然。

在此输入图像描述


To be honest, I haven't followed you example very well. 说实话,我没有很好地跟着你。 I think you are confusing the idea of collections with design patterns. 我认为你将收藏的想法与设计模式混为一谈。

Mixing the logic of the two, in my opinion, would be muddying the programming logic behind using either pattern. 在我看来,混合两者的逻辑将混淆使用任一模式背后的编程逻辑。 Although design patterns may not be clear cut, this is particular example that I cannot (off the top of my head) think of a useful application. 虽然设计模式可能不是很明确,但这是一个特殊的例子,我不能(在我的头脑中)想到一个有用的应用程序。 If there are useful examples, I am sure someone will pipe up. 如果有有用的例子,我相信有人会说清楚。

Yes, I agree with your understanding of facade - A Facade's intention is to provide a new & simplified interface (or access point or gateway) to a complex system. 是的,我同意您对外观的理解 - Facade的目的是为复杂系统提供新的简化界面(或接入点或网关)。 Or a unified interface to hide multiple sub-systems. 或者是统一的界面来隐藏多个子系统。

Now, I'll answer your questions one by one - 现在,我将逐一回答您的问题 -

So my first question is if I am correct that you would implement the "interface" as a class? 所以我的第一个问题是,如果我是正确的,你将把“接口”作为一个类来实现?

When we use "interface" in context of facade, it refers to API , conveying a meaning of - point of interaction or point of contact . 当我们在立面的上下文中使用“接口”时,它指的是API ,传达了 - 交互 接触 点的含义。 The facade acts as point of contact between client & complex system. 外观充当客户端和复杂系统之间的联系点

Now, how to implement the facade ? 现在,如何实现立面? certainly you can use c# interface to define the functions, events, properties that the facade will expose to client. 当然,您可以使用c# interface来定义Facade将向客户端公开的函数,事件和属性。 The actual wrapper will be a class realizing this interface . 实际的包装器将是一个实现此interfaceclass

Even if the complex system you are hiding is static, wrapping static system in a class realizing interface , will be helpful while implementing unit tests. 即使您隐藏的复杂系统是静态的,在实现interfaceclass包装静态系统,在实现单元测试时也会有所帮助。

My other question then is, could you use facade pattern together with the observer pattern. 我的另一个问题是,你可以将外观模式与观察者模式一起使用。 The facade class would observe on all subjects and then control what methods in different classes should be called, depending on the subject? Facade类将观察所有主题,然后根据主题控制不同类中应该调用哪些方法?

From a scemantic purity point of view, a facade should only define new APIs on existing API of the wrapped sub-system. 从语言纯度的角度来看,外观应该只在包装的子系统的现有API上定义新的API。

If the system you are hiding needs a publisher-subscriber model, you would have to implement observer pattern in your facade, wrapping the publisher-subscriber calls of the sub-system. 如果您隐藏系统需要发布者 - 订阅者模型,则必须在外观中实现观察者模式,包装子系统的发布者 - 订阅者调用。

However, don't add more responsibilities or logic to facade than needed to in the name of simplicity, think of it as a fairly simple advocate or facilitator for the sub-system, nothing more. 但是,不要以简单的名义为门面添加更多的职责或逻辑,将其视为子系统的相当简单的倡导者或推动者,仅此而已。 It should not become an all-knowing "god" object. 它不应该成为一个无所不知的“上帝”对象。

Which leads me to thinking that it doesn't really make sense to do it with a facade, as the whole point of the facade is to make it easier for the client right? 这让我觉得用门面做这件事真的没有意义,因为门面的重点是让客户更容易吗? (or hide information) or am I wrong? (或隐藏信息)或我错了?

In your example, all this logic should not be in facade. 在您的示例中,所有这些逻辑都不应该在外观中。 I agree it'll make it easier for client, but its not built over the wrapped sub-system, its like an additional service the facade is offering. 我同意它会让客户更容易,但它不是建立在包装的子系统上,而是像门面提供的附加服务。 So take this out from facade into a separate class, the client can use that class to make its life easy. 因此,从外观进入一个单独的类,客户端可以使用该类来使其生活轻松。

If there is anything in a facade that you think can be taken out of facade, without exposing the sub-system, then that thing must be taken out of facade. 如果您认为外立面中有任何东西可以从外立面中取出而不暴露子系统,则必须将该外观取出。

Hope it helps. 希望能帮助到你。 Please write me a comment if any bit is unclear or you think I have missed any of your questions & we can take it from there. 如果有任何不清楚或者你认为我错过了你的任何问题我们可以从那里拿走它,请给我写评论。

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

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