【问题标题】:Combining two modules without making the factory a god object结合两个模块而不使工厂成为上帝对象
【发布时间】:2015-03-11 20:40:36
【问题描述】:

我们有一个应用程序可以联系几个不同的远程服务(SOAP、HTTPREQUEST)。然后我们执行不同的操作(导入、导出、更新、删除)。

今天我们有两个客户端类四个操作类

问题!
我怎样才能解耦这两个模块,以便我必须做最少的更改。 IE 只添加一个新动作/新客户端。仅此而已。

客户端类
针对远程服务授权我们的客户端,它处理登录和注销。

动作类
保存要针对客户端调用的 url,方法。以及 ExecuteActionMethod

用法
客户端类 get 装饰有一个动作,然后与客户端一起执行该动作。

恐惧
我不想:
- 每次添加新的客户端类时创建一个新的动作类
- 创建一个新的客户端类 每次我添加一个新的动作类
- 没有需要知道一切的上帝对象工厂

问题
这种方法的问题是,当与不同的客户端交谈时,我需要不同的信息,在这种情况下不同的 URL,与 Soap 服务交谈需要调用正确的方法。 操作本身就是这些信息的保存者。但随着我深入挖掘,这肯定会发生变化。

场景1#
我最终创建了结合了动作和结果的类。所以我有像“HttpImport”这样的类(基于 HttpClient 和 ImportAction)。这导致 X(Clients) * Y(Actions) 现在将 总共 8 个类,这真的很糟糕。
场景2#
是时候写一些代码了!在这种情况下,即使我使用抽象,实现也会将我的类绑定在一起。

这里的问题是每个动作都需要为每个客户端拥有一个属性(记住它们访问不同的端点)。因此,如果我要再添加一个 client 我将不得不执行所有操作并为该客户端端点添加另一个属性,以及添加另一个 deocrator 以将所有调用委托给正确的端点(记住我现在在每个动作中都有三个属性)。如果我要创建另一个动作,那就是那个动作。所以 N*次动作 + 1(动作),在这种情况下 5 变化。稍微好一点,但还没有。

场景3#
这是上帝对象工厂。在这里,我们摆脱了保存端点的属性,并通过构造函数提供了端点。这将产生用于创建各种客户端和操作的方法。同上X(Clients) * Y(Actions),如果要添加一些东西,这些会在工厂内部累积成8个新方法。工厂还必须保存端点信息。

代码
我的代码已经发展到 2:nd 场景。我不想建工厂,我在找你们。

有些事情告诉我,客户端类做了很多事情,应该以某种方式将它们与它们在内部实例化的类分离。

主要

static void Main(string[] args)
{
        IAction iact = new ImportAction();
        IDecorator idec = new HttpDecorator(iact);
        IClient icli = new HttpClient(idec);

        Console.Write(icli.connect().ToString());
        Console.ReadKey();
}

IAction

public interface IAction
{
    string[] Execute();
    string HttpString { get; }
    string SoapMethod { get; }
}

ImportAction

class ImportAction : IAction
{
    private string soapmethod;
    private string httpUrl;
    public ImportAction()
    {
        this.HttpString = @"http://www.hereiswereactionsgo.com";
    }   
    public string[] Execute()
    {   //Execute the action!
        return null;
    }
    public string HttpString { get; set; }
    public string SoapMethod { get; set; }
}

IDecorator

public interface IDecorator
{
    string GetActionString();
}

HttpDecorator

class HttpDecorator : IDecorator
{
    private IAction _action;
    public HttpDecorator(IAction action)
    {
        this._action = action;
    }
    public string GetActionString()
    {
        return _action.HttpString;
    }
    public string[] Execute()
    {
        throw new NotImplementedException();
    }
}

IClient

public interface IClient
{
    bool connect();
}

HttpClient

class HttpClient : IClient
{
    private string _username;
    private string _password;
    private IDecorator _myaction;
    private HttpWebRequest webReq;

    public HttpClient(IDecorator action)
    {
        this._username = "myusername";
        this._password = "mypassword";
        this._myaction = action;   
    }

    public bool connect()
    {
        bool result = false;
        webReq = (HttpWebRequest)WebRequest.Create(_myaction.GetActionString());
        webReq.Credentials = new NetworkCredential(_username, _password);
        HttpWebResponse myHttpWebResponse = (HttpWebResponse)webReq.GetResponse();

        if (myHttpWebResponse.StatusCode == HttpStatusCode.OK)
        {
            result = true;
        }

        return result;
    }

}

【问题讨论】:

    标签: c# design-patterns module decorator


    【解决方案1】:

    Visitor 模式似乎适合这个 (Visitor)。 将操作视为访问者,将客户视为要访问的元素。通过提供样板代码,将 Action 保留为抽象类而不是接口可能会有所帮助。

    • 添加一个新的操作扩展BaseAction。实现getHttpUrl()getHttpBody()等方法
    • 添加新客户端需要更改现有类。您必须在每个 Action 类中实现相应的方法。我假设添加新客户端的频率会降低。

    下面的示例代码遵循 Java 语法。

    public static void main() {
      new HttpClient().performAction(new ImportAction());
    }
    
    public interface Client {
      performAction(Action);
    }
    
    public class HttpClient implements Client {
      public void accept(IAction a) {
        a.visitHttp(this);
      }
    }
    
    public abstract class Action {
      public visitHttp(HttpClient c) {
         getHttpUrl();
         c.connect(getHttpUrl());
         c.send(getHttpBody());
         c.close;
      }
    
      public visitSoap(SoapClient c) {
    
      }
    
      public abstract String getHttpUrl();
      public abstract String getHttpBody();
    }
    
    ImportAction extends Action {
      @Override
      getHttpUrl() {
    
      }
    
      @Override
      getHttpBody() {
    
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-04-30
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 2010-12-07
      • 2023-03-19
      相关资源
      最近更新 更多