问题描述
我以Java为例,但这更多是与OOP设计相关的一般问题.
I use Java as an example but this is more of a general OOP design related question.
让我们以Java中的IOException
为例.例如为什么会有一个类FileNotFoundException
?那不应该是原因是FileNotFound
的IOException
的实例吗?我会说FileNotFoundException
是IOException
的实例.这在哪里结束? FileNotFoundButOnlyCheckedOnceException
,FileNotFoundNoMatterHowHardITriedException
..
Lets take the IOException
s in Java as an example. Why is there a class FileNotFoundException
for example? Should not that be an instance of a IOException
where the cause is FileNotFound
? I would say FileNotFoundException
is an instance of IOException
. Where does this end? FileNotFoundButOnlyCheckedOnceException
, FileNotFoundNoMatterHowHardITriedException
..?
我也曾在存在FirstLineReader
和LastLineReader
这样的类的项目中看到过代码.对我而言,此类实际上代表了实例,但是我在许多地方都看到了这种设计.例如,以Spring Framework源代码为例,它附带了数百个此类,每当我看到一个这样的类时,我都会看到一个实例而不是一个蓝图.难道课堂不是蓝图吗?
I have also seen code in projects I worked in where classes such as FirstLineReader
and LastLineReader
existed. To me, such classes actually represent instances, but I see such design in many places. Look at the Spring Framework source code for example, it comes with hundreds of such classes, where every time I see one I see an instance instead of a blueprint. Are not classes meant to be blueprints?
我想问的是,如何在这两个非常简单的选项之间做出决定:
What I am trying to ask is, how does one make the decision between these 2 very simple options:
选项1:
enum DogBreed {
Bulldog, Poodle;
}
class Dog {
DogBreed dogBreed;
public Dog(DogBreed dogBreed) {
this.dogBreed = dogBreed;
}
}
选项2:
class Dog {}
class Bulldog extends Dog {
}
class Poodle extends Dog {
}
第一个选项使调用者可以配置正在创建的实例.在第二个选项中,该类已经表示了实例本身(如我所见,这可能是完全错误的..).
The first option gives the caller the requirement to configure the instance it is creating. In the second option, the class represents the instance itself already (as I see it, which might be totally wrong ..).
如果您同意这些类代表实例而不是蓝图,那么您是否会说创建一个代表实例的类是一种好习惯,还是我看待这个和我的陈述"类代表的方式是完全错误的实例" 只是废话吗?
If you agree that these classes represent instances instead of blueprints, would you say it is a good practice to create classes that represents instances or is it totally wrong the way I am looking at this and my statement "classes representing instances" is just load of nonsense?
推荐答案
已编辑
首先:我们知道继承定义,并且可以在SO和Internet中找到很多示例.但是,我认为我们应该深入研究 ,并且要更加科学.
Edited
First of all: We know the Inheritance definition and we can find a lot of examples in SO and internet. But, I think we should look in-depth and a little more scientific.
注释0 :
关于继承和实例术语的说明.
首先,当我们对系统进行建模和编程时,我将其命名为 Development Scope (开发范围),有时将其命名为 Runtime Scope .
Note 0:
Clarification about Inheritance and Instance terminology.
First let me name Development Scope for development life cycle, when we are modeling and programming our system and Runtime Scope for sometimes our system is running.
我们在开发范围中有类,建模和开发它们.和对象在运行时范围. 开发范围中没有对象.
We have Classes and modeling and developing them in Development Scope. And Objects in Runtime Scope. There is no Object in Development Scope.
在面向对象中,实例的定义是:从类创建对象.
And in Object Oriented, the definition of Instance is: Creating an Object from a Class.
另一方面,在讨论类和对象时,我们应阐明关于开发范围和运行时范围的观点.
On the other hand, when we are talking about classes and object, we should clarify our Viewpoint about Development Scope and Runtime Scope.
因此,在本次介绍中,我想阐明继承:
继承是类无对象之间的关系.
继承可以存在于Development Scope中,而不存在于Runtime Scope中.运行时作用域中没有继承.
So, with this introduction, I want to clarify Inheritance:
Inheritance is a relationship between Classes, NOT Objects.
Inheritance can exist in Development Scope, not in Runtime Scope. There is no Inheritance in Runtime Scope.
运行我们的项目后,父子之间没有任何关系(如果子类和父类之间只有继承).因此,问题是:什么是super.invokeMethod1()
或super.attribute1
?,它们不是孩子与父母之间的关系.父级的所有属性和方法都传输给子级,这只是访问父级传输的部分的一种表示法.
After running our project, there is no relationship between parent and child (If there is only Inheritance between a child class and parent class). So, the question is: What is super.invokeMethod1()
or super.attribute1
?, they are not the relationship between child and parent. All attributes and methods of a parent are transmitted to the child and that is just a notation to access the parts that transmitted from a parent.
此外,Development Scope中没有任何对象.因此,开发范围中没有任何实例.这只是是-A 和具有-A 的关系.
Also, there are not any Objects in Development Scope. So there are not any Instances in Development scope. It is just Is-A and Has-A relationship.
因此,当我们说:
我们应该澄清我们的范围(开发和运行时).
例如,如果FileNotFoundException
是IOException
的实例,那么运行时特定的FileNotFoundException
异常(对象)与FileNotFoundException
之间的关系是什么.是实例的实例吗?
We should clarify about our Scope (Development and Runtime).
For example, If FileNotFoundException
is an instance of IOException
, then what is the relationship between a specific FileNotFoundException
exception at runtime (the Object) and FileNotFoundException
. Is it an instance of instance?
注释1 :
我们为什么使用继承?继承的目标是扩展父类功能(基于相同的类型).
Note 1:
Why we used Inheritance? The goal of inheritance is to extending parent class functionalities (based on the same type).
- 可以通过添加新属性或新方法来进行此扩展.
- 或覆盖现有方法.
- 此外,通过扩展父类,我们也可以达到可重用性.
- 我们不能限制父类的功能(Liskov原理)
- 我们应该能够在系统中将孩子替换为父母(Liskov原理)
- 等等
注释2 :
继承层次结构的宽度和深度
继承的宽度和深度可能与许多因素有关:
Note 2:
The Width and Depth of Inheritance Hierarchies
The Width and Depth of Inheritance can be related to many factors:
- 项目:项目的复杂性(类型复杂性)及其架构和设计.项目规模,班级数量等.
- 团队:团队在控制项目复杂性方面的专业知识.
- 等等
但是,我们对此有一些启发. (面向对象的设计启发式技术,Arthur J. Riel)
However, we have some heuristics about it. (Object-Oriented Design Heuristics, Arthur J. Riel)
在实践中,继承层次不应深于 一个普通人可以保留他或她的短期记忆.受欢迎的 该深度的值是6.
In practice, inheritance hierarchies should be no deeper than an average person can keep in his or her short-term memory. A popular value for this depth is six.
请注意,它们是启发式的,基于短期记忆数(7).也许团队的专业知识会影响这个数字.但是在许多层次结构中都使用了组织结构图.
Note that they are heuristics and based on short-term memory number (7). And maybe the expertise of a team affect this number. But in many hierarchies like organizational charts is used.
注释3 :
何时使用错误继承?
基于:
Note 3:
When we are using Wrong Inheritance?
Based on :
- 注1:继承的目标(扩展父类功能)
- 注意2:继承的宽度和深度
在这种情况下,我们使用了错误的继承:
In this conditions we use wrong inheritance:
-
我们在继承层次结构中有一些类,没有扩展的父类功能. 扩展名应该合理,并且足以开设一个新班级.从观察者的角度来看,合理的手段.观察者可以是项目架构师或设计师(或其他架构师和设计师).
We have some classes in an inheritance hierarchy, without extending parent class functionalities. The extension should be reasonable and should be enough to make a new class. The reasonable means from Observer's point of view. The observer can be Project Architect or Designer (Or other Architects and Designers).
我们在继承层次结构中有很多类.它称为过度专业化.某些原因可能导致这种情况:
We have a lot of classes in the inheritance hierarchy. It calls Over-Specialization. Some reasons may cause this:
- 也许我们没有考虑注释1 (扩展父功能)
- 也许我们的模块化(包装)不正确.并且我们将许多系统用例放在一个程序包中,我们应该进行设计重构.
- Maybe we did not consider Note 1 (Extending parent functionalities)
- Maybe our Modularization (packaging) is not correct. And we put many system use cases in one package and we should make Design Refactoring.
这是其他原因,但与该答案不完全相关.
They are other reasons, but not exactly related this answer.
注释4 :
我们该怎么办?当我们使用错误继承时?
Note 4:
What should we do? When we are using Wrong Inheritance?
解决方案1:我们应该执行设计重构以检查类的值,以便扩展父功能.在此重构中,可能删除了许多类的系统.
Solution 1: We should perform Design Refactoring to check the value of classes in order to Extending parent Functionality. In this refactoring, maybe many classes of system deleted.
解决方案2:我们应该执行设计重构"以实现模块化.在此重构中,也许我们包的某些类传递给了其他包.
Solution 2: We should perform Design Refactoring to modularization. In this refactoring, maybe some classes of our package transmitted to other packages.
解决方案3::使用继承组合.
出于多种原因,我们可以使用此技术. 动态层次结构是我们更喜欢使用合成"而不是继承"的常见原因之一.
请参见(Sun的Tim Boudreau)的注释此处:
Solution 3: Using the Composition over Inheritance.
We can use this technique for many reasons. Dynamic Hierarchy is one of popular reasons that we prefer Composition instead of Inheritance.
see Tim Boudreau (of Sun) notes here:
解决方案4:在子类上使用实例
这个问题是关于这种技术的.让我将其命名为子类上的实例.
Solution 4: use instances over Subclasses
This question is about this technique. Let me named it instances over Subclasses.
何时可以使用它:
-
(技巧1):当我们没有完全扩展父类功能时,请考虑注释1.否则扩展名不够合理.
(Tip 1): Consider Note 1, when we do not exactly extend the parent class functionalities. Or the extensions are not reasonable and enough.
(技巧2:):请注意注释2,如果我们有很多子类(半类或相同类)扩展了父类一点,并且我们可以控制此扩展而无需继承.请注意,说起来并不容易.我们应该证明它没有违反其他面向对象的原则,如开放-关闭原则.
(Tip 2:) Consider Note 2, If we have a lot of subclasses (semi or identical classes) that extends the parent class a little and we can control this extension without inheritance. Note that it is not easy to say that. We should prove that it is not violating other Object Oriented Principles like Open-Close Principle.
我们应该怎么做?
马丁·福勒(Martin Fowler)建议(书1 第232页和书2 第251页):
What should we do?
Martin Fowler recommend (Book 1 page 232 and Book 2 page 251):
我们可以使用诸如enum
之类的其他技术来解决上述问题.
We can use other techniques like enum
as the question mentioned.
这篇关于类的实例和已经表示一个实例的类之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!