用于创建一组数据对象的设计模式

时间:2010-10-08 16:10:47

标签: c# .net design-patterns

我正在编写一些代码来做一些事情,我很确定它目前没有很好的设计,但我想不出我应该如何重构它以使其更好......

简单的总结是我有一些代码遍历目录结构中的某些文件,不同的目录包含不同的内容类型。我有这些内容类型的数量有限,目前我有一个内容类型对象,我只是通过以下方式创建了很多要添加到列表中的内容:

        contentTypes.Add(new ContentType { ContentName = "2010 Call Report", FolderName = "2010 Reports", RenameFile = false });
        contentTypes.Add(new ContentType { ContentName = "2010 Email Report", FolderName = "2010 Reports", RenameFile = false });
        contentTypes.Add(new ContentType { ContentName = "Above Average Call Recording", FolderName = "Call Recordings", RenameFile = true, HasMultiple = true });
        contentTypes.Add(new ContentType { ContentName = "Below Average Call Recording", FolderName = "Call Recordings", RenameFile = true, HasMultiple = true });

这真的感觉不对(共有11行几乎完全相同的代码),但我想不出我还应该做些什么。

ContentType类包含上面可以看到的一些属性和一个名为GetNewFilename的公共方法。目前,GetNewFilename方法非常简单,并且由所有内容类型共享。但是,我现在想让一些ContentType个对象拥有自己的此方法版本......

我考虑过的事情是:

1)子类ContentType为每种内容类型创建一个类

这对我来说似乎不对,因为我有11个课程,所有这些课程都没有改变他们的信息,而且从来没有任何一个课程。这对于一个班级来说是不一样的(我知道单身人士,但听说如果你使用它们,你可能会错误地做错了。)

<{1}}

上的

2)Func属性

我认为我可以在ContentType上设置一个代理来处理ContentType函数的不同,但它仍然会以上述方式产生它们而感到混乱。

3)工厂类

我以前从未使用过Factory类(据我所知),但我知道它们用于生成类。我对它们的阅读表明,这种模式用于生成不同的子类型,而不仅仅是一组类的实例。

4)配置文件

我上面提到的数据都可以放在配置文件或数据库或其他东西中然后加载并循环以更好地生成它(这只是发生在我身上)但它仍然无法解决变化GetNewFilename方法的问题。我不确定我是否可以轻松地将委托放在配置文件中。 :)

5)在一个类上拥有所有不同的getNewFileName方法

我可以让内容类拥有我想要的所有不同方法,并使用某种选择然后选择正确的方法。这似乎也忽略了这一点。

那么有人可以建议一个好方法吗?

以下是我getNewFilename课程的当前签名(逻辑被删除 - 询问您是否认为相关)。

ContentType

如果你想了解如何使用这个类的更多细节,那么问我可以粘贴它但我不想在代码中淹没我认为不相关的类。

这仅适用于一次使用的代码(将文件移动到适当的目录以放置在新网站上并确保它们被正确命名)所以最好的代码并不重要,但是如果我的话它会给我带来麻烦至少不知道我应该做什么。如果正确的方式看起来会花费太长时间(例如从头开始重写代码),那么我不会打扰,但至少我下次会知道。 :)

P.S。我现在也意识到,一个或两个构造函数来设置这些初始值并将它们设置为只读将是一个适当的改变,以便将它连接起来,但仍然无法解决我的所有问题。

3 个答案:

答案 0 :(得分:2)

让您的ContentType类成为基类并使GetNewFilename方法成为虚拟。从ContentType类导出可能需要在GetNewFilename方法中进行特殊处理的每种文件类型,并覆盖虚拟实现。然后,只需在目录搜索中找到需要特殊处理的文件类型时,根据需要创建这些继承类的实例,否则只需创建ContentType类的实例。

public class ContentType
{
    public virtual string GetNewFilename(string originalFilename, int fileIndex)
    {
        // get file name here
    }
}

public sealed class SpecialContentType : ContentType
{
    // Inherrits all the properties of ContentType

    public override string GetNewFilename(string originalFilename, int fileIndex)
    {
        // get special file name here
    }
}

答案 1 :(得分:1)

要考虑的另一种模式可能是接口或抽象类。是的,你有11个班级,但这不一定是坏事。它会让你的问题保持清晰分离,同时仍然提供一个共同的框架。

如果GetFileName在几种情况下的工作方式相同,则可以使用虚拟GetFileName方法实现抽象类。这将限制您必须编写的新代码量,仅在必要时覆盖:

public abstract class ContentType
    {
        public string ContentName { get; set; }
        public string FolderName { get; set; }
        public bool RenameFile { get; set; }
        public bool HasMultiple { get; set; }

        public virtual string GetFileName()
        { 
            //Base GetFileName implementation
            return "filename";
        }
    }

答案 2 :(得分:1)

对于#4,你可以使用像Unity或StructureBuilder这样的IoC容器。然后提供第二部分的课程:

public interface INewFilenameService {
  string FileName {get;set;}
}

public class ContentType {
    private INewFilenameService newFilenameService;

    public ContentType(INewFilenameService service) {
        this.newFilenameService = service;
    }

    public string ContentName { get; set; }
    public string FolderName { get; set; }
    public bool RenameFile { get; set; }
    public bool HasMultiple { get; set; }

    public string GetNewFilename() {
      return service.Filename;
    }
}

然后您可以在config或运行时实例化您的内容类型列表。