使用策略从超类创建子类

时间:2015-10-28 13:40:08

标签: c# oop design-patterns architecture

我有一个与C#/ OO / Design相关的问题。

我正在重新设计一个移植到C#的旧系统。我们正在重构系统,使其更简单,更面向对象。

在这个系统中,我们有各种与我们的业务领域相关的对象 - 文件夹,文档,用户,约会,任务等。所有这些对象都从一个被调用的基础对象继承,信不信由你,BaseObject:

public class BaseObject {
    public int Id { get; set; }
    public string Name { get; set; }
}

这个对象不是抽象的,因为我们实际上是为一些简单的列表实例化它。

我们也有自己的通用列表:

public class CustomList<T> : IENumerable<T> where T : BaseObject {
    //... several properties and methods

    }
}

我的问题是:我有很多从BaseObject继承的对象。例如,我可以创建CustomList<User>,因为User : BaseObject

但是,我的许多用户控件都返回CustomList<BaseObject>,因为这是大多数基于列表的用户控件可以返回的内容:它们知道每个对象的名称,因为它们显示的是什么,并且它们使用其ID作为键

因此,我希望能够将CustomList<BaseObject>中的项目添加到任何CustomList<T>。我希望能够添加对象,而不仅仅是构建一个新列表。

但是因为我不能只是从超类(BaseObject)转换为子类(例如User),所以我在考虑在CustomList<T>中实现以下方法:

public void AddRangeOfBaseObjects(IEnumerable<BaseObject> items, Func<BaseObject, T> constructor)
    {
        foreach (var item in items)
        {
            var newObject = constructor(item);
            Add(newObject);
        }
    }

或者换句话说,如果一个类需要从CustomList创建一个CustomList,它需要提供CustomList和一个方法,说明如何从BaseObject构造T的每个新实例,以及如何初始化其他成员哪个BaseObject不知道。

我认为这类似于策略模式。当然这个方法本身几乎没有任何代码,但是由于这种行为无处不在,设计它的时间仍然更短。

问题是 - 这是一个好的设计吗?是否有更好的模式来处理将简化版本的对象从UI移动到实际对象的情况?

1 个答案:

答案 0 :(得分:2)

基本上,您已经实现了类似于Linq的Select函数的某种功能 map 函数。如今很多人都喜欢功能风格而不是普通的OOP。您的AddRangeOfBaseObjects(IEnumerable<BaseObject> items, Func<BaseObject, T> constructor)是一种简单而干净的方式,可以满足您的需求。

使用Linq的另一种方式可能是

public static CustomList<T> ToCustomList<T>(this IEnumerable<T> items)
    where T : BaseObject
{
    var customList = new CustomList<T>();
    foreach(var item in items)
        customList.Add(item);
}

然后像

一样使用它
IEnumerable<BaseObject> items = ...;
Func<BaseObject, T> constructor = ...;

// Usage would be
CustomList<T> customItems = 
    (from i in items
     select constructor).ToCustomList();

// or
CustomList<T> customItems = items.Select(constructor).ToCustomList();

不创建新列表

public void AddRangeOfBaseObjects(IEnumerable<BaseObject> items, Func<BaseObject, T> constructor)
{
    // AddRange from List<T>
    AddRange(items.Select(constructor);
}