我使用Java作为示例,但这更像是一般的OOP设计相关问题.
让我们以IOException
Java中的s为例.为什么有一个类FileNotFoundException
例如?难道不应该是一个实例IOException
,其中的原因是FileNotFound
?我想说的FileNotFoundException
是一个例子IOException
.这到底在哪里?FileNotFoundButOnlyCheckedOnceException
,FileNotFoundNoMatterHowHardITriedException
..?
我也看到过我所在的项目中的代码,其中包括类FirstLineReader
和LastLineReader
存在的类.对我来说,这些类实际上代表了实例,但我在很多地方看到了这样的设计.以Spring Framework源代码为例,它带有数百个这样的类,每次看到一个我都看到一个实例而不是蓝图.这些课程不是蓝图吗?
我想问的是,如何在这两个非常简单的选项之间做出决定:
选项1:
enum DogBreed {
Bulldog, Poodle;
}
class Dog {
DogBreed dogBreed;
public Dog(DogBreed dogBreed) {
this.dogBreed = dogBreed;
}
}
Run Code Online (Sandbox Code Playgroud)
选项2:
class Dog {}
class Bulldog extends Dog {
}
class Poodle extends Dog {
}
Run Code Online (Sandbox Code Playgroud)
第一个选项为调用者提供了配置它正在创建的实例的要求.在第二个选项中,类已经表示了实例本身(正如我所看到的,这可能是完全错误的......).
如果你同意这些类代表实例而不是蓝图,你会说创建表示实例的类是一个好习惯,或者我正在看这个是完全错误的,我的语句"表示实例的类"只是加载废话?
Gho*_*ani 18
首先:我们知道继承定义,我们可以在SO和互联网上找到很多例子.但是,我认为我们应该深入而且更加科学.
注0:
关于继承和实例术语的说明.
首先让我为开发生命周期命名开发范围,当我们对系统和运行时范围进行建模和编程时,有时我们的系统正在运行.
我们有类和建模,并在开发范围内开发它们.和运行时范围内的对象.开发范围中没有对象.
在面向对象中,实例的定义是:从类创建对象.
另一方面,当我们谈论类和对象时,我们应该澄清关于开发范围和运行时范围的观点.
因此,通过这个介绍,我想澄清继承:
继承是类,非对象之间的关系.
继承可以存在于开发范围中,而不是存在于运行时范围中.运行时范围中没有继承.
在运行我们的项目之后,父项和子项之间没有任何关系(如果子类和父类之间只有继承).所以,问题是:什么是super.invokeMethod1()
或super.attribute1
?,他们不是孩子和父母之间的关系.父节点的所有属性和方法都传输给子节点,这只是访问从父节点传输的部分的符号.
此外,开发范围中没有任何对象.因此,开发范围中没有任何实例.它只是Is-A和Has-A的关系.
因此,当我们说:
我想说的
FileNotFoundException
是一个实例的IOException
我们应该澄清我们的范围(开发和运行时).
例如,If FileNotFoundException
是一个实例IOException
,那么FileNotFoundException
运行时特定异常(Object)与之间的关系是什么FileNotFoundException
.它是实例的实例吗?
注1:
为什么我们使用继承?继承的目标是扩展父类功能(基于相同类型).
注意2:
继承层次结构
的宽度和深度继承的宽度和深度可以与许多因素相关:
但是,我们有一些启发式方法.(面向对象的设计启发式,Arthur J. Riel)
从理论上讲,继承层次结构应该越深越深越好.
在实践中,继承层次结构应该不比一般人可以保留在他或她的短期记忆中更深.这个深度的流行价值是六.
请注意,它们是启发式的,基于短期记忆编号(7).也许团队的专业知识会影响这个数字.但在许多层次结构中使用了组织结构图.
注3:
当我们使用错误的继承?
基于 :
在这种情况下,我们使用错误的继承:
我们在继承层次结构中有一些类,没有扩展父类功能.扩展应该是合理的,应该足以创建一个新类.从观察者的角度来看,这是合理的手段.观察者可以是项目建筑师或设计师(或其他建筑师和设计师).
我们在继承层次结构中有很多类.它称为过度专业化.一些原因可能导致:
他们是其他原因,但这个答案并不完全相关.
注4:
我们该怎么办?当我们使用错误的继承?
解决方案1:我们应该执行Design Refactoring来检查类的值,以便扩展父功能.在这种重构中,可能删除了许多类系统.
解决方案2:我们应该执行设计重构以进行模块化.在这个重构中,我们的包的一些类可能会传输到其他包.
解决方案3:使用Composition over Inheritance.
我们可以使用这种技术有很多原因.动态层次结构是我们更喜欢使用Composition而不是Inheritance的常见原因之一.
看到Tim Boudreau(太阳报)在这里注意到:
对象层次结构不可扩展
这个问题是关于这种技术的.让我将它命名为Subclasses上的实例.
当我们可以使用它时:
(技巧1):当我们没有完全扩展父类功能时,请考虑注1.或者扩展名不够合理.
(技巧2 :)考虑注2,如果我们有很多子类(半类或相同的类),它们稍微扩展了父类,我们就可以在没有继承的情况下控制这个扩展.请注意,这并不容易.我们应该证明它并没有违反开放式原则等其他面向对象原则.
我们应该做什么?
Martin Fowler建议(第1册第232页和第2册第251页):
用字段替换子类,将方法更改为超类字段并消除子类.
我们可以使用其他技术,如enum
提到的问题.