Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 我应该使用继承吗?_Oop_Inheritance_Class Design - Fatal编程技术网

Oop 我应该使用继承吗?

Oop 我应该使用继承吗?,oop,inheritance,class-design,Oop,Inheritance,Class Design,这更像是一个主观问题,所以我要先把它标记为社区维基 基本上,我发现在我的大部分代码中,有许多类,其中许多类相互使用,但很少有类彼此直接相关。回顾我的大学时代,我想到了传统的猫:动物类的例子,你有巨大的继承树,但我在我的代码中没有看到这些。我的类图看起来像巨大的蜘蛛网,不像漂亮的树 我觉得我在逻辑上分离信息方面做得很好,最近我通过DI/IoC技术隔离了类之间的依赖关系,但我担心我可能遗漏了一些东西。我确实倾向于在接口中聚集行为,但我只是没有子类化 我可以很容易地理解传统示例中的子类化,例如类Dog

这更像是一个主观问题,所以我要先把它标记为社区维基

基本上,我发现在我的大部分代码中,有许多类,其中许多类相互使用,但很少有类彼此直接相关。回顾我的大学时代,我想到了传统的猫:动物类的例子,你有巨大的继承树,但我在我的代码中没有看到这些。我的类图看起来像巨大的蜘蛛网,不像漂亮的树

我觉得我在逻辑上分离信息方面做得很好,最近我通过DI/IoC技术隔离了类之间的依赖关系,但我担心我可能遗漏了一些东西。我确实倾向于在接口中聚集行为,但我只是没有子类化

我可以很容易地理解传统示例中的子类化,例如
类Dog:Animal
类Employee:Person
,但我没有任何明显的东西。而且事情很少像
类标签:Control
那样清晰。但是,当涉及到在我的代码中将真实实体建模为层次结构时,我不知道从哪里开始

所以,我想我的问题可以归结为:

  • 简单地不使用子类或继承可以吗?我应该担心吗
  • 您有哪些策略来确定可以从继承中受益的对象
  • 总是基于行为(接口)而不是实际类型进行继承是否可以接受

  • 继承应始终表示“是一种”关系。如果A源于B,你应该能说“A是B”。如果不是,你更喜欢构图。当不需要子类时,不使用子类是完全可以的

    例如,说
    FileOpenDialog
    是一个
    窗口
    是有意义的,但说
    引擎
    “是一辆
    汽车
    是毫无意义的。在这种情况下,在
    汽车
    实例中的
    发动机
    实例更合适(可以说
    汽车
    ”是根据“
    发动机
    ”实现的)

    有关继承的详细讨论,请参阅gotw.ca上的“继承的使用和滥用”

  • 只要你不错过清晰的“是a”关系,这没关系,事实上,最好不要继承,而是使用组合

  • is-a是石蕊试验。如果(X是Y吗?)那么
    class X:Y{}
    else
    class X{Y myY;}
    class Y{X myX;}

  • 使用接口,即继承行为,是通过只添加所需行为而不添加其他行为来构造代码的一种非常简洁的方法。棘手的部分是很好地定义这些接口


  • 我也讨厌狗->哺乳动物->动物的例子,正是因为它们没有出现在现实生活中

    我很少使用子类,因为它将子类与超类紧密地结合在一起,使您的代码很难阅读。有时实现继承很有用(例如PostgreSQLDatabaseImpl和MySQLDatabaseImpl扩展AbstractSQLDatabase),但大多数时候它只是把事情弄得一团糟。大多数时候,我看到子类的概念被误用,应该使用接口或属性

    然而,接口是很好的,你应该使用它们。

    IMHO,你永远不应该这样做#3,除非你专门为此目的构建一个抽象基类,并且它的名称清楚地说明了它的用途:

    class DataProviderBase {...}
    class SqlDataProvider : DataProviderBase {...}
    class DB2DataProvider : DataProviderBase {...}
    class AccountDataProvider : SqlDataProvider {...}
    class OrderDataProvider : SqlDataProvider {...}
    class ShippingDataProvider : DB2DataProvider {...}
    
    等等

    同样遵循这种类型的模型,有时如果您提供一个接口(
    IDataProvider
    ),那么最好也提供一个基类(
    DataProviderBase
    ),未来的使用者可以使用它方便地访问应用程序模型中所有/大多数数据提供者通用的逻辑


    不过,作为一般规则,只有在我拥有真正的“is-a”关系时,或者如果创建“is-a”关系(例如提供者模型)可以改善总体设计时,我才使用继承。

    任何技术或模式都不应该为了自身的目的而使用。显然,您工作的领域中的类往往无法从继承中获益,因此不应该使用继承

    你用DI来保持东西整洁。你把你班上的事分开了。这些都是好事。如果你真的不需要继承,就不要试图强迫继承


    这个问题的一个有趣的后续问题是:哪些编程领域倾向于很好地利用继承?(已经提到了UI和db框架,它们都是很好的例子。还有其他的吗?

    你的三个问题的答案都是“视情况而定”。最终,这一切都取决于您的域以及您的程序如何处理它。很多时候,我发现我选择使用的设计模式实际上有助于找到继承工作良好的地方

    例如,考虑用一个“变压器”来将数据推入所需的形式。如果您将3个数据源作为CSV文件,并希望将它们放入三个不同的对象模型中(并可能将它们持久化到数据库中),则可以创建一个“CSV transformer”库,然后在继承时重写某些方法,以便处理不同的特定对象

    将开发过程“转换”到模式语言中可以帮助您找到行为相似的对象/方法,并有助于减少冗余代码(可能通过继承,也可能通过使用共享库——以最适合的情况为准)


    此外,如果将层(业务、数据、表示等)分开,类图将更简单,然后可以“可视化”那些无法继承的对象

    在共享功能的地方,编程到接口比继承更重要

    本质上,继承更多的是将对象关联在一起

    大多数时候我们都很自负
    class Product
    class Article
    class NewsItem
    
    // A collection decorator that is-a collection with 
    public class MyCustomCollection implements java.util.Collection {
        private Collection delegate;
        // decorate methods with custom code
    }