1

更新:几乎这里的每个人都告诉我,我只需要重新开始我如何设计我的课程(顺便感谢你们的出色回答!)。得到提示后,我开始广泛阅读策略模式。我想创建从一个或多个抽象基类继承的行为类(或策略类)。然后,候选类将具有带有不同抽象基类/类的属性作为Type行为或策略。也许是这样的:

public abstract class SalaryStrategy {
    public abstract decimal Salary { get; set; }
    public abstract decimal Min { get; set; }
    public abstract decimal Mid { get; set; }
    public decimal CompaRatio {
        get {
            if (this.Mid == 0) { return 0; }
            else { return this.Salary / this.Mid; }
        }
    }
}

public class InternalCurrentSalaryStrategy {
    public override decimal Salary { get; set; }
    public override decimal Min {
        get { return this.Salary * .25m; }
        set { }
    }
    public override decimal Mid { get; set; }
}

public class Candidate {
    public int Id { get; set; }
    public string Name { get; set; }
    public SalaryStrategy CurrentSalaryStrategy { get; set; }
}

public static void Main(string[] args) {
    var internal = new Candidate();
    internal.CurrentSalaryStrategy = new InternalCurrentSalaryStrategy();
    var internalElp = new Candidate();
    internalElp.CurrentSalaryStrategy = new InternalCurrentSalaryStrategy();
    var elp = new Candidate();
    // elp.CurrentSalaryStrategy can stay null cause it's not used for elps
}

有什么意见或建议吗?


原始问题:

我正在努力学习并更加精通设计模式和原则。我目前正在为一些让我难过的课程进行设计。这是代码的非常精简的版本:

public class Candidate {
    public int Id { get; set; }
    public string Comments { get; set; }
    // lots more properties and behaviors...
}

public class InternalCandidate : Candidate {
    public decimal CurrentMid { get; set; }
    public decimal CurrentMax {
         get { return this.CurrentMin * 1.3m;
    }
    // lots more properties and behaviors...
}

public class EntryLevelCandidate : Candidate {
    public string Gpa { get; set; }
    // lots more properties and behaviors...
}

public class InternalEntryLevelCandidate /* what do I inherit here??? */ {
    // needs all of the properties and behaviors of
    // EntryLevelCandidate but also needs the CurrentMin and
    // CurrentMax (and possibly more) in InternalCandidate
}

InternalEntryLevelCandidate 类主要是一个EntryLevelCandidate,但需要共享InternalCandidate 的一些实现。我说实现是因为我不希望实现不同或重复,否则我会使用通用合同的接口并在每个类中都有具体的实现。InternalCandidate 属性和行为的一些实现需要通用或共享。我已经阅读了 C++ 和 Ruby mixins,这似乎与我想做的类似。我还阅读了这篇有趣的博客文章,其中讨论了一种行为类型的想法,其中一个类能够继承多个行为,同时仍然保持单一的“是”关系:http://www.deftflux.net/blog/post/A-good-design-for-multiple-implementation-inheritance.aspx。这似乎传达了我想要的东西。谁能给我一些指导,告诉我如何使用良好的设计实践来实现这一目标?

4

5 回答 5

5

不可变的数据值类。 如果您的各种候选子类中的任何属性代表某种有意义的数据值,请为其创建一个不可变类,并具有您需要的行为。然后,每个不同的 Candidate 子类都可以使用该数据类型,但您的代码仍封装在数据类中。

扩展方法。 这些可以重载以与任何类一起使用。

我会避免使用装饰器模式并坚持编译/反射功能。

作品。 立即在单独的类中开发独特的行为,并围绕它们构建候选类,而不是在候选类中编写独特的行为并尝试提取它们的功能以供以后在相关类中使用。

根据您使用类的方式,您还可以实现并使用显式和隐式转换运算符到相关类型,因此您可以实际将对象转换为类型/实现,而不是重新实现接口(您想避免)无论出于何种目的,您都需要。

我刚刚想到的与最后一段相关的另一件事是拥有一个租赁系统,您的类在其中产生和适当类型的对象,允许对其进行操作,然后稍后使用它以吸收更新的信息。

于 2009-04-29T23:45:06.007 回答
4

这是一篇我认为非常有趣的关于该主题的学术论文(PDF 链接)。

但是,我认为您正试图在概括中强加业务逻辑。您碰巧知道内部候选人永远不会查看他的 GPA。但是,内部候选人肯定有 GPA。所以,你已经破解了这个叫做 InternalEntryLevelCandidate 的奇怪家伙,因为你碰巧知道你想查看这个家伙的 GPA。在架构上,我认为 EntryLevelCandidate 是不正确的。我会为候选人添加一个“级别”概念并给他一个 GPA。由业务逻辑决定他们是否查看 GPA。

编辑:另外,Scott Meyers在他的书中很好地剖析了这个问题。

于 2009-04-29T23:31:39.470 回答
2

免责声明

根据我的经验,需要多重继承是例外而不是规则,仔细设计类层次结构通常可以避免需要这个特性。我同意 JP 的观点,即可以在您的样本中避免此要求。

回到问题,没有干净的解决方案,但是您有几个选择:

  • 使用扩展方法,缺点是右键Resolve不起作用,还有一些人真的不喜欢这些小狗。

  • 创建一个聚合对象,其中包含您想要组合的每个类的实例,重新实现委托的存根方法。

  • 为每个行为定义一个接口,并让基础中的方法在this is IInterface执行行为之前检查是否。(允许您将行为定义拉到基础)

近乎重复: C# 中的多重继承

于 2009-04-29T23:28:13.723 回答
1

我同意继承在这里似乎不是正确的事情。我不确定我是否知道完美的答案,但也许装饰器模式是合适的。

另一个更深奥的想法是考虑面向方面的编程。你可以用方面做一些非常了不起的事情,但这是一个我还没有掌握的非常高级的话题。像 Rikard Oberg 和他的Qi4J同伙这样的人。

于 2009-04-29T23:16:01.380 回答
0

我只是使用委托模式。最终我会为每个不同的功能使用一个接口,然后有一个具体的类作为每个接口的委托。然后你的最终类只使用他们需要的委托,并且可以从多个接口继承。

public class InternalEntryLevelCandidate : EntryLevelCandidate {
    private  InternalCandidate internalCandidateDelegate
        = new InternalCandidate();

    public decimal CurrentMid { 
        get { return internalCandidateDelegate.CurrentMid; }
        set { internalCandidateDelegate.CurrentMid = value; }
    }

    public decimal CurrentMax {
        get { return internalCandidateDelegate.CurrentMax }
    }
}
于 2009-04-29T23:46:20.480 回答