如何重构这个?

时间:2009-10-19 13:05:10

标签: c# design-patterns

关于如何将其重构为一个体面的模式,我正在努力解决一个小问题。

public class DocumentLibrary
{
    private IFileSystem fileSystem;
    private IDocumentLibraryUser user;

    public DocumentLibrary(IDocumentLibraryUser user) : this(user, FileSystemFrom(user)) { }

    public DocumentLibrary(IDocumentLibraryUser user, IFileSystem fileSystem)
    {
        this.user = user;
        this.fileSystem = fileSystem;
    }

    public void Create(IWorkerDocument document)
    {
        document.SaveTo(fileSystem);
    }

    public IWorkerDocument AttemptContractRetrieval()
    {
        return new Contract(fileSystem, user);
    }

    public IWorkerDocument AttemptAssignmentRetrieval()
    {
        return new Assignment(fileSystem, user);
    }

    private static IFileSystem FileSystemFrom(IDocumentLibraryUser user)
    {
        var userLibraryDirectory = new DirectoryInfo("/DocLib/" + EnvironmentName() + "/" + user.Id);
        return new FileSystem(userLibraryDirectory);
    }

    private static string EnvironmentName()
    {
        using (var edmxContext = new Entities())
        {
            return (from setting in edmxContext.EnvironmentSettings
                         where setting.Name == "EnvironmentName"
                         select setting.Value).First(); 
        }
    }
}

我有两种类型的工作文档,但我似乎无法轻易地将上述两种方法(AttemptContractRetrievalAttemptAssignmentRetrieval)重构为一种体面的形式。

非常感谢任何帮助。

此致 吉姆。

6 个答案:

答案 0 :(得分:5)

在个人情况下,我会考虑使用工厂方法的工厂模式或构建器模式。

在Enterprise Library解决方案中可以看到工厂模式的良好使用,例如: Database.CreateDatabase();
我想说这将是最直接的整合。

如果您选择了构建器模式,并且需要创建更复杂的对象,那么您可以将复杂对象的创建分离为一系列构建命令,例如: vehicleBuilder.BuildFrame(); vehicleBuilder.BuildEngine(); vehicleBuilder.BuildWheels(); vehicleBuilder.BuildDoors();

然后在这些方法中,根据您选择的实现,您可以添加您的复杂性,但是方法调用和构造非常直接。

如果您没有遇到过,http://www.dofactory.com是一个不错的去处。

答案 1 :(得分:1)

我可以看到两个方面:

  1. 添加新的IWorkerDocument类需要做什么?添加新方法似乎很重要。
  2. 调用者需要什么代码才能创建IWorkerDocument?现在调用正确方法的责任在于调用者,因此每次有新的IWorkerDocument实现者时,调用者很可能也需要更改。
  3. 可能的重构程度在很大程度上取决于2的答案。有时调用者只需知道他们正在制作什么,在这种情况下,你拥有的代码几乎就是你所能做的。在其他情况下,您有一些“WorkerDefinition”内容,可能是一组Properties的形式,或者可以在注册表中查找的名称。在这种情况下,调用者想要一个

    形式的api
     makeMeAWorker(WorkerDefinition def)
    

    在工厂。现在,来电者不知道他要求的是什么,将整个事情委托给工厂。因此,当您添加新的Worker类型时,客户端的世界不需要更改。

    可以通过某种形式的注册方案或动态配置方案使工厂可扩展。我们可以通过许多不同的机制将新类型注入工厂。

答案 2 :(得分:1)

我认为这取决于该类包含这些方法的其他职责。设计模式是结构构造。在这里我们推断出有一个类

class Retriever
{
  ...
  public IWorkerDocument AttemptContractRetrieval()
  {
  }

  public IWorkerDocument AttemptAssignmentRetrieval()
  {
  }
}

客户端代码已经决定是否调用AttemptContractRetrieval()或AttemptAssignmentRetrieval,因此可能是多态性。

class ContractRetriever
{
   public IWorkerDocument AttemptRetrieval()
   {
   }
}

class AssignmentRetriever
{
   public IWorkerDocument AttemptRetrieval()
   {
   }
}

您可以创建一个抽象的Retriever类,并将其作为后代。这将强制派生类具有AttemptRetrieval()方法。

如果对检索到的文档执行类似操作,则可以考虑使用Contract和Assignment类而不是ContractRetriever和AssignmentRetriever。然后你可以将共同的行动放在他们的父母身上。

简而言之,这里的答案很多都在于问题的未说明背景。

答案 3 :(得分:1)

对于感兴趣的人,我去了一个工厂方法。

public IWorkerDocument AttemptRetrieval<T>() where T : IWorkerDocument
{
    return WorkerDocument.Create<T>(fileSystem, user);
}

来电

public static IWorkerDocument Create<T>(IFileSystem fileSystem, IDocumentLibraryUser user) where T : IWorkerDocument
{
    var documentType = typeof(T);
    if (documentType == typeof(Contract))
        return new Contract(fileSystem, user);
    if (documentType == typeof(Assignment))
        return new Assignment(fileSystem, user);
    throw new Exception("Invalid Document Type");
 }

这有点乱,所以有人有任何建议来清理实际的工厂方法吗?

答案 4 :(得分:0)

怎么样:

  public IWorkerDocument AttemptRetrieval<T>() where T:new, IWorkerDocument
     {
         return new T {FileSystem=fileSystem,User=user}
     }

在我的头顶,所以可能包含明显的错误; - )

答案 5 :(得分:0)

您在寻找抽象工厂模式吗? “设计模式”中声明的意图是“提供用于创建相关或依赖对象族的接口,而无需指定其具体类。”

http://en.wikipedia.org/wiki/Abstract_factory