【问题标题】:How should I abstract a collection of objects owned by another object?我应该如何抽象另一个对象拥有的对象集合?
【发布时间】:2011-12-22 23:49:18
【问题描述】:

在一个管理职业培训的系统中,我有一个 CourseBase 抽象类,我决定使用它来支持 ICourse 接口,因为我希望避免重复从假设派生的所有类的实现代码,基础Course 实体。每门课程都有一个主题列表,其中任何主题都由SubjectBase 抽象类定义。所以,我有例如

public abstract class CourseBase : BaseObject
{
    public IEnumerable<SubjectBase> Subjects
    {
        get { return new List<SubjectBase>(); }
    }   
}

public abstract class SubjectBase
{
    public string Name { get; set; }
    public string Description { get; set; }
    public int ValidityPeriod { get; set; }
}

现在我想添加一个具体的类LocalCourse,它包含LocalCourseSubject 对象的集合,但是因为我没有使用CourseBase 的接口,所以我失去了协方差,我需要用我的新属性隐藏抽象基的 Subjects 属性:

public class LocalCourse: CourseBase
{
    public IEnumerable<LocalCourseSubject> Subjects
    {
        get { throw new NotImplementedException(); }
    }
}

我确信从 OO 的角度来看,我在这里遗漏了一些非常明显的东西,但我能看到的唯一解决方案是:

  1. 从抽象基础中完全省略 Subjects,只向派生类添加特定类型的集合属性。
  2. 在抽象基类和具体类中实现一个接口,例如ISubjectCollectionOwner

请原谅我的昏暗,我已经有一段时间没有遇到这样的设计问题了。

【问题讨论】:

  • 您使用的是哪个版本的 C# 和 .NET?它在通用方差方面有所不同。顺便说一句,你真的需要这里的所有抽象吗?你会有哪些不同类型的课程和科目?
  • 不是 SubjectBase 的重点,因此您可以使用多态性对待所有主题。难道你不能摆脱你的主题覆盖并使用 CourseBase 主题集合吗?
  • @Jon, v4 在这两个方面。我在这里的“规范”是为了迎合“各种事物”,所以我只是在赌尽早获得足够的抽象来支持对基本实体的广泛扩展。
  • @Cosmin,我想你可能有一些我刚刚忽略的东西。谢谢,我去看看。

标签: c# .net oop ooad


【解决方案1】:

为什么不引入通用接口来抽象课程?对不起,如果我错过了一些明显的东西

public interface ICourse<TSubject>
{
   IEnumerable<TSubject> Subjects { get; }
}

public abstract class CourseBase<TSubject> 
   : BaseObject, 
     ICourse<TSubject>
{
    public IEnumerable<TSubject> Subjects
    {
        get { return new List<TSubject>(); }
    }   
}

public class LocalCourse 
   : CourseBase<LocalCourseSubject>
{
}

如果 Subject 是 Course 实体的重要组成部分,您也应该将其保留在 ICourse 和 CourseBase 中,否则我建议通过 ISubjectAware 接口对其进行抽象

【讨论】:

  • 我认为这是个坏主意。上面的@Cosman 有正确的想法。像这样使用泛型会破坏多态性,您将无法以泛型方式处理主题集合。
  • 我不确定我是否做对了 - you won't be able to handle the collection of subjects in a generic way,你能举个例子吗?
  • 如果这是 .Net-4.0 之前的版本,我可以给你举个例子。但我刚刚接受了协方差方面的培训,并做了类似“IEnumerable objs = new List();”之类的事情。是可能的。这很有趣,可能会改变我未来的对象模型设计。抱歉打扰了。
【解决方案2】:

你不能这样做吗:

public abstract class CourseBase<T> where T : SubjectBase
{
    public virtual IEnumerable<T> Subjects
    {
        get { return new List<T>(); }
    }
}

public abstract class SubjectBase
{
    public string Name { get; set; }
    public string Description { get; set; }
    public int ValidityPeriod { get; set; }
}

public class LocalCourse : CourseBase<LocalCourseSubject>
{
    public override IEnumerable<LocalCourseSubject> Subjects
    {
        get { throw new NotImplementedException(); }
    }
}

我认为无论如何,这将实现您的短期目标,假设一般模式是每个 CourseBase 继承者都将具有相同类型的 SubjectBase 继承者的集合。但是,如果是这样的话,这似乎是一个并行继承层次结构,有时可能是一种代码味道(并不是说它一定是——我不知道你正在建模的域的所有细节)。

【讨论】:

  • 看起来我正在建模的域的所有者甚至不清楚细节,但是谢谢,这是一个很好的候选人。
  • 很高兴它在某种程度上有所帮助。 :)
猜你喜欢
  • 2012-07-18
  • 1970-01-01
  • 1970-01-01
  • 2019-08-26
  • 1970-01-01
  • 2012-01-08
  • 2019-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多