2

我创建了一个具有通用方法的父类,但有些方法我希望由子类实现。即单击执行方法。

实现这一点的正确方法是什么?

public Parent {
    CancelCommand = new RelayCommand(CancelClicked, CancelCanExecute);
    private void CancelClick(object param) {
        // Do stuff
    }
}

public Child : Parent {
    private bool CancelCanExecute(object param) {
        // Do stuff
        return true;
    }
}

其中 CancelClick 由父类托管,而 CancelCanExecute 由子类处理。

我会使用外部人员吗?或者我应该使用接口?如果我在子类中使用覆盖,它不会强迫我必须实现该方法。我不确定是否应该将父类更改为抽象类,因为它具有非抽象方法等。

4

4 回答 4

4

因此,这是您的选择:

1.声明你的基类abstract一些方法

这种方法有两个好处:您可以在基类中自由地实现通用方法(也就是说,并非所有方法都需要abstract),而任何抽象方法都必须在派生类中被覆盖。有一个反驳点(您可能知道):您无法实例化它。也就是说,您不能执行以下操作:

Base obj = new Base();

但是,您仍然可以这样做:

Base obj = new Child();

2.使用接口

你可以声明一些接口来强制你的类实现一些方法。但是,继承和接口之间的语义是完全不同的。您必须决定哪个最适合您。

恕我直言,您可以选择第一个选项。

于 2012-08-28T17:57:14.053 回答
3

您需要在 Parent 中指定一个抽象方法:

public abstract class Parent
{
    public void DoSomething()
    {
        // Do something here...
    }

    public abstract void ForceChildToDoSomething();
}

这迫使孩子实现它:

public class Child : Parent
{
    public override void ForceChildToDoSomething()
    {
        // Do something...
    }
}

但是,您现在将有一个抽象的 Parent。因此,如果您想使用 Parent 中的功能,您需要执行以下操作:

Parent parent = new Child();
parent.DoSomething();
parent.ForceChildToDoSomething();
于 2012-08-28T17:58:18.933 回答
1

是的,摘要:

public abstract Parent
{
  protected abstract bool CancelCanExecute(object param);
  //more stuff
}

也可能是public,但不是private

现在你不能有一个既不实现又不实现的派生类,它CancelCanExecute本身abstract就迫使进一步的派生类来实现它。

于 2012-08-28T17:59:55.797 回答
1

您应该定义一个接口,然后您的代码应该只接受实现该接口的对象。虽然使用abstract和创建公共基类非常诱人,但这种方法(几乎)根据定义(几乎)是错误的。

在 C# 和其他不允许多重继承的语言中,创建一个基类只是为了定义一个其他人必须填充的空“骨架”并强制每个人使用它是非常有限的。每个人都必须继承它,因此,例如,他们将无法重用自己现有的类层次结构,或者必须创建乏味的桥梁或 (...)。

如果您的抽象基类除了一个/几个/几十个/数百个抽象方法、事件和属性之外什么都没有——它应该是一个接口,因为它只定义了“通用要求”。

使用通用事物创建新抽象基础的唯一合理理由是实际提供默认实现。尽管如此,对于这样的基类,也应该定义一个接口,基类应该实现它并允许覆盖甚至可能将某些东西标记为实际上是抽象的——但您的代码仍然应该通过接口引用所有内容,而不是基类。这样的抽象基础应该是实现者的帮助/快捷方式,而不是强制性的。如果有人想从头开始做所有事情 - 他将实现接口并忽略示例代码的基础,您的代码仍然可以很好地使用它。尽管如此,所有通用代码都可以作为一组在该接口上运行的静态帮助程序类提供。

抽象基类实际上是需要的,并且在某些极端情况下不能被接口取代,例如,当您必须强制派生类具有参数构造函数时,或者您自己必须从某些东西派生时,即。像 WPF Visual 或 UIElement 或 DependencyObject --- 因此微软的设计在这里也有一点缺陷。他们强制从基类派生,它在许多地方影响了开发人员(例如,来自 EntityFramework 的数据模型对象不是 DependencyObjects 等)。尽管如此,我认为他们应该从中抽象出来——看看 Visual 和朋友,没有多少内部例程不能提升到接口。我不认为他们这样做只是“因为”,而是,我认为它是关于性能和削减演员/方法调度。

请注意,我所说的一切并不完全符合您在问题中提出的内容。在那里,您已经假设“父/基类将处理 XYZ”。这意味着,您从一开始就放弃了界面方法。使用接口,您将只定义 click 和 cancelclick 必须存在,但您将无法强制/提供“基本实现”。这些事情你可以用基类来做。因此,我认为您应该采取开放/混合的方法:定义接口,定义静态可重用处理程序,仅使用接口,并为一些“懒惰的编码器”提供基类:

public interface IClickable
{
    ICommand CancelCommand { get; }
    void CancelClick();
    bool CanCancelClick();
}

public static class ClickableDefaultImpl
{
    public static void DefaultCancelClick(IClickable obj)
    {
        ... do the common things on the OBJ
    }
    public static bool DefaultCanCancelClick(IClickable obj)
    {
        ... do the common things on the OBJ
    }
}

public abstract class Clickable : IClickable
{
    public void CancelClick() { ClickableDefaultImpl.CancelClick(this); }
    public bool CanCancelClick() { return ClickableDefaultImpl.CanCancelClick(this);  }
}

这可能看起来很臃肿,但它对定制非常开放。尽管具有开放性,但几乎没有办法强制每个人都必须使用“ClickableImpl”。有一些方法,但是..它们会包括更多的膨胀和时间/内存开销,我认为它们现在不值得描述。

请记住估计将来将使用此代码的人员、方式和数量。如果是用于一/二/五用途,请坚持使用抽象基础。但是如果你感觉到有几十个或几百个子实现,你最好加上那个小膨胀——以后可能会节省很多时间。

于 2012-08-28T18:13:09.053 回答