3

我了解组合优于继承的优势。除其他外,它使单元测试(和模拟)更容易,您的代码不与基类耦合等。我还观看了关于可测试、干净代码的精彩演讲,通过这样的优秀图片成功地将这些想法留在了我的脑海中:

在此处输入图像描述

尝试了解释抽象类含义的帖子,但我仍然不清楚:由于我可以通过接口实现多态行为,并且我可以通过组合将任务委托给我的依赖项,我应该在哪里使用抽象类,甚至是基础具体上课?

4

4 回答 4

2

一个优点是方便。抽象类可以提供默认实现。您可以只覆盖您想要的方法,而根本不需要实现所有其他方法。

例如,Java 的 MouseListener 接口有五个方法;抽象类 MouseAdapter 提供了这些的默认实现。基于扩展抽象类 MouseAdapter 的实现只需要实现所需的方法。

另一个优点是超类方法调用可以调用子类方法。例如,C++ 非虚拟习语使用它来允许超类方法在委托给子类方法之前和之后强制执行方法协定。

于 2013-05-27T22:56:57.300 回答
1

如果您取消了抽象类,您将如何以可重用的方式实现接口的一部分?您将创建一个接口和一些辅助类来执行您可以委托给的实现,但是这个辅助类不会实现该接口,因此不清楚它是否与该接口相关。你会解耦太多。

或者,您会让人们完全实现接口,以便其他人知道它具有基本实现,但随后他们将不得不做一些黑客行为以指示必须覆盖某些方法(例如,在调用它们时抛出异常) .

抽象类提供了一种简洁的方式来提供接口以及对编译器和其他工具可见的接口的部分实现。

于 2013-05-27T22:50:21.470 回答
0

对于需要共享实现的情况,抽象类仍然非常有用,而不是接口(在一般意义上)。

例如,考虑模板方法设计模式。这是一个共享实现的例子。算法的大部分是在抽象基类中实现的,但某些部分是由子类提供的。这些子类只需要扩展它们的基类并在其中实现抽象模板方法即可完成工作。

将此与策略模式进行对比,其中整个算法是抽象的,并且实现被批量注入到需要它们使用委托/组合的类中。这是一个共享接口的例子。尽管算法本身可能完全不同,但它们都实现了相同的基本操作。

于 2013-05-27T22:58:22.533 回答
0

即使您使用了组合,继承仍然有用。恕我直言,这明确适用于框架架构。

  • 门面父类

    您可以使用外观类将您的组合包装在继承上。示例将是:

    public class Parent : IService
    {
        public Parent(IService1 s1, IService2 s2)
        {
    
        }
    }
    
    public class Child : Parent
    {
        public Child()
            : base(Service1, Service2)
        {
    
        }
    
        private static IService1 Service1
        {
            get
            {
                // return Service1
            }
        }
    
        private static IService2 Service2
        {
            get
            {
                // return Service2
            }
        }
    }
    

    源语法。这个外观类,可以用作默认功能对象,在框架级对象中很有用。然后,如果再次继承,您可以只扩展一种方法的功能,其余的保持原样。

  • 扩展第三方库

    并非所有第三方库都使用依赖注入。为了扩展功能,您经常需要继承它(例如:)System.Windows.Forms.Form。尤其是自定义Framework级别(企业级),最好继承。如果框架发生变化,您覆盖的其他方法也将被更改,而不是使用组合。虽然它可能是双刃剑。

于 2013-05-28T03:14:10.923 回答