面向对象编程的立面

时间:2018-02-02 02:22:12

标签: oop design-patterns

在OOP中, Facade 应该是对象还是?哪个更好?

Wikipedia中的大多数示例都将Facade创建为一个对象,应在使用前进行实例化。

CarFacade cf = new CarFacade();
cf.start();

可以设计成这样吗?

CarFacade.start();

更新

Facade能否促成单身人士?

3 个答案:

答案 0 :(得分:4)

门面

  • 表示复杂子系统(模块)的高级API。
  • 减少客户端代码依赖性。

    这意味着您的客户端代码仅使用外观并且确实如此 没有很多依赖于该门面背后的类。

最好使用接口的实例,因为

  • 您可以将其替换为测试。例如。模拟外观代表的子系统。
  • 您可以在运行时替换它。

当您使用静态方法时,您的客户端代码在编译时绑定到该方法实现。这通常与open/close principle相反。

我说“通常相反”,因为有些例子使用静态方法,但系统仍然可以进行扩展。 E.g。

  • ServiceLoader

    静态加载方法仅扫描类路径和查找服务实现。因此,在类路径中添加类和META-INF/services描述将添加其他可用服务,而无需更改ServiceLoader代码。

  • Spring的AuthenticationFacade例如在内部使用ThreadLocal。这样就可以替换AuthenticationFacade的行为。因此它也可以扩展。

最后,我认为最好使用像我在大多数其他类中使用的实例和界面。

答案 1 :(得分:1)

它是双重的。您可以将其用作静态方法。比如在Spring安全性中,我使用AuthenticationFacade来访问当前登录的用户Principal详细信息。 AuthenticationFacade.getName()

还有其他一些实例,其中大多数人创建Facade实例并使用它。在我看来,这两种方法都没有优势。相反,它取决于你的背景。

最后,Facade可以使用Singleton模式来确保它只创建一个实例并提供一个全局访问点。

答案 2 :(得分:1)

这个问题非常主观。我回应的唯一原因是因为我查看了一些自己的代码,并发现我在一个应用程序中将Façade写成单例,并在需要实例的不同应用程序中编写了几乎相同的Façade。我将讨论为什么我在各自的应用程序中选择这些路由,以便我可以评估我是否做出了正确的选择。

@Rene Link已经解释了外观与开放/关闭原则。根据我的个人经验,你必须这样想:对象是否保持自身的状态?

假设我有一个包装Azure Storage API for .NET(https://docs.microsoft.com/en-us/azure/storage/common/storage-samples-dotnet)的外观

此Facade包含有关如何对存储API进行身份验证的信息,以便客户端可以执行以下操作:

Azure.Authenticate(username, password);
Azure.CreateFile("My New Text File", "\\FILELOCATION");

正如您在本示例中所看到的,我还没有创建实例,而且我正在使用静态方法,因此遵循单例模式。虽然这使得代码更简洁,但是如果我需要使用与已经提供的凭证不同的凭证对给定路径进行身份验证,我现在有一个问题,我将不得不这样做:

Azure.Authenticate(username, password)
Azure.CreateFile("My New Text File", "\\FILELOCATION");

Azure.Authenticate(username2, password2);
Azure.CreateFile("My Restrictied Text File", "\\RESTRTICTEDFILELOCATION");

虽然这会起作用,但是当我调用Azure.ReadFile时很难确定身份验证失败的原因,因为我不知道哪些用户名和密码可能已从form2上的thread4传递到单例中(这是否定的在哪里找到)这是您应该使用实例的一个主要示例。自从做这样的事情后,它会做得更多:

Using (AzureFacade myAzure = Azure.Authenticate(username, password)) 
{
    Azure.CreateFile("My New Text File", "\\FILELOCATION"); // I will always know the username and password.
}

话虽如此,如果开发人员需要在Azure中创建一个不知道Azure的用户名和密码可能是什么的方法,会发生什么。一个很好的例子是定期连接到Azure并执行一些多线程任务的应用程序。在所述应用程序中,用户将连接字符串设置为azure,并且使用该连接字符串执行所有多线程任务。因此,不需要为每个线程创建一个实例(因为对象的状态将始终相同)但是,为了保持线程安全,您不希望在所有线程之间共享相同的实例。这是单线程,线程安全模式可能发挥作用的地方。 (根据@Rene Link,Spring AuthenticationFacade)所以我可以做这样的事情(psudocode)

Thread[] allTask = // Create 5 threads

Azure.Authenticate(username, password) // Authenticate for all 5 threads.

allTask.start(myfunction)

void myFunction() 
{
    Azure.CreateFile("x");
}

因此,在façade与单体外观的实例之间进行选择完全取决于外立面的预期应用,但两者都可以存在。