【问题标题】:Facade Pattern, is this ok?门面图案,可以吗?
【发布时间】:2011-09-29 22:21:39
【问题描述】:

我有两台服务器,我将从一个客户端连接到它们。对于每台服务器,我都会做一个 ftp "put" 和一个 "rm"。

我是否应该构建一个外观,并拥有这样的界面:

void putFileOnServer1(String file)
void putFileOnServer2(String file)
void removeFromServer1(String file)
void removeFromServer2(String file)

而且,立面应该处理所有连接的建立和断开连接吗? 如果是这样,它应该使用工厂这样做吗?

【问题讨论】:

  • 您是想挑选一些模式来融入您的设计,还是想了解在设计特定解决方案时哪些模式是常见的?前者会导致设计糟糕的解决方案,而后者可能需要更多关于您要解决的问题的详细信息。

标签: facade


【解决方案1】:

您有两个方法,PutFileOnServer 和 RemoveFromServer。您要放置或删除的服务器应该是抽象的一部分。

【讨论】:

  • 我没看到,我怎么告诉门面我想把文件放在哪个服务器上?
  • 老实说,如果您只有 2 台服务器并且它们都是 FTP,那么您应该有一个类,并且该类的两个实例因 FTP 设置而异。如果它们仅在 FTP 设置上有所不同,则不应为每个 FTP 服务器创建一个类。
  • 谢谢,学习一下,如果有 100 台服务器,你会怎么做?
  • 创建 100 个因 FTP 设置而异的类实例。我永远不会创造 100 种不同的类型!
  • 所以继续传递所需的连接设置?
【解决方案2】:

ftp 服务器是否有不同的接口?还是他们都理解您想要使用的同一组命令?

  1. 如果是这样,那么只需创建一个接受连接信息的FtpServer 类。并创建一个接受多个服务器的FtpClient 类,例如,您可以通过某些键进行选择。 (至少在某种程度上,这可能是我会做的事情)。

    class FtpClient
    {
        public function addServer( FtpServer $server, $key );
    
        public function selectServer( $key );
    
        public function putFileOnServer( $file );
    
        public function removeFileFromServer( $file );
    }
    
  2. 如果没有,并且您已经为每个单独的实现提供了一个类,它们的接口不同,例如:

    class FtpServerFoo
    {
        public function selectFile( $file );
        public function removeSelectedFile();
    }
    
    class FtpServerBar
    {
        public function removeFile( $file );
    }
    

    ...您应该查看Adapter Pattern:

    abstract class FtpServer
    {
        abstract public function putFile( $file );
        abstract public function removeFile( $file );
    }
    
    class FtpServerAdapterFoo
        extends FtpServer
    {
        public function __construct( FtpServerFoo $server )
        {
        }
    
        public function removeFile( $file )
        {
            $this->server->selectFile( $file );
            $this->server->removeSelectedFile();
        }
    }
    
    class FtpServerAdapterBar
        extends FtpServer
    {
        public function __construct( FtpServerBar $server )
        {
        }
    
        public function removeFile( $file )
        {
            $this->server->removeFile( $file );
        }
    }
    
    $cilent = new FtpClient();
    $client->addServer( new FtpServerAdapterFoo( new FtpServerFoo() ), 0 );
    $client->addServer( new FtpServerAdapterBar( new FtpServerBar() ), 1 );
    
    $client->selectServer( 0 );
    $client->putFileOnServer( $file );
    
    $client->selectServer( 1 );
    $client->removeFileFromServer( $someOtherfile );
    
  3. 如果您还没有针对不同 FTP 服务器的单独类,那么您可以为每个 ftp 服务器实现实现相同的接口(或继承一个抽象类),并再次使用与上述相同类型的 FtpClient 类.

    但这里并不真正涉及外观模式。

【讨论】:

    【解决方案3】:

    您通常使用外观来降低多种对象类型之间的复杂性。但是,在这种情况下,您似乎只想使用一种功能“类型”,即“FTPServer”。那么,在大多数情况下,您应该只有两个这种类型的实例,并且这种类型将有一个“put”和“remove”方法。

    当您添加不必要的功能点时,实际上会增加维护的复杂性。例如,如果您需要为您的函数添加一个新参数(可能是访问限制或其他),您不仅需要针对每个使用地点进行更改,而且现在必须添加每个外观方法。抽象应该减少这种类型的耦合,而不是增加它。

    【讨论】:

    • 那么每个 ftp 服务器都有一个门面吗?
    • 不,外观似乎并没有给你任何东西,只是在这里增加了复杂性。您只是添加方法而不添加功能。这种对现有职责的重复只会增加后期维护。在这里根本不要使用门面,因为没有理由。只需使用普通的日常用品即可。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-20
    相关资源
    最近更新 更多