![]() |
1
11
简短的回答:是的,这是可能的。但你必须有目的地去做,而不是偶然(使用final、抽象和考虑继承的设计等)。 ) 长答案: 好吧,继承实际上不是为了“代码重用”,而是为了类的“专门化”,我认为这是一种误解。 例如,仅仅因为向量相似,就从向量创建堆栈是一个非常糟糕的主意吗。或者来自HashTable的属性,因为它们存储值。见[有效]。 “代码重用”更多的是OO特性的“业务视图”,这意味着您的对象很容易在节点之间分布;并且是可移植的,没有前一代编程语言的问题。事实证明,这有一半是正确的。我们现在有了可以轻松分发的库;例如,在java中,jar文件可以用于任何项目,从而节省数千小时的开发时间。OO在可移植性等方面仍然存在一些问题,这就是现在WebServices如此受欢迎的原因(就像以前的CORBA一样),但这是另一个线程。 这是“代码重用”的一个方面。另一个是有效的,与编程有关。但在这种情况下,不仅仅是“保存”代码行和创建脆弱的怪物,而是在设计时考虑到继承。这是前面提到的书中的第17项; 第17项:设计和文件以供继承,否则禁止继承。 参见[有效] 当然,你可能有一个Car类和大量的子类。是的,你提到的关于Car接口、抽象Car和CarImplementation的方法是正确的。 你定义了汽车应该遵守的“合同”,并说这些是我在谈论汽车时所期望的方法。抽象汽车具有每辆汽车的基本功能,但留下并记录了子类负责处理的方法。在java中,您可以通过将方法标记为抽象来实现这一点。 当你这样做时,“脆弱”类没有问题(或者至少设计者有意识或有威胁),子类只完成设计者允许的部分。 继承更多的是“专门化”类,就像卡车是汽车的专门版本一样,MosterTruck是卡车的专门版本。 从汽车创建“计算机鼠标”子类并不是因为它有一个像汽车一样的轮子(滚轮),它会移动,下面有一个轮子只是为了节省代码行。它属于另一个域,将用于其他目的。 防止“实现”继承的方法是从一开始就在编程语言中,你应该在类声明中使用final关键字,这样你就禁止了子类。 如果是故意进行的,子分类并不是坏事。如果做得不小心,可能会变成一场噩梦。我会说,你应该尽可能地从私密和“最终”开始,如果需要的话,让事情变得更加公开和可扩展。这也在演示文稿“如何设计好的API以及为什么它很重要”中得到了广泛解释参见[好的API] 继续阅读文章,随着时间的推移和练习(以及极大的耐心),这件事会变得更清楚。虽然有时你只需要做这项工作并复制/粘贴一些代码:P。这没关系,只要你先把它做好。 以下是Joshua Bloch(以前在Sun工作,从事java核心工作,现在为Google工作)的参考资料 [有效] 有效的Java。绝对是非初学者应该学习、理解和实践的最好的java书。A必须有。
[好的API]介绍API的设计、可重用性和相关主题。 它有点长,但每一分钟都值得。 How To Design A Good API and Why it Matters 当做。
更新:看看我发给你的视频链接的第42分钟。它谈到了这个话题: “当你在一个公共API中有两个类,并且你想让一个成为另一个的子类,就像Foo是Bar的子类一样,问问你自己,每个Foo都是Bar吗?…” 在前一分钟,它在谈论TimeTask时谈到了“代码重用”。 |
![]() |
2
8
大多数反对继承的例子的问题是,人们错误地使用了继承,而不是继承未能正确抽象。 在您发布的链接中,作者使用Stack和ArrayList展示了继承的“破碎性”。这个例子是有缺陷的,因为 堆栈不是数组列表 因此不应使用继承。该示例与字符串扩展字符或PointXY扩展数字一样有缺陷。 在扩展类之前,您应该始终执行“is_a”测试。既然你不能说Every Stack是一个ArrayList而不存在某种错误,那么你就不应该使用它。 Stack的合约与ArrayList(或List)的合约不同,堆栈不应该继承不关心的方法(如get(int i)和add())。事实上,Stack应该是一个具有以下方法的接口:
像ArrayListStack这样的类可能实现Stack接口,在这种情况下,使用组合(具有内部ArrayList)而不是继承。 继承并不坏,坏的继承是坏的。 |
![]() |
3
4
你也可以使用组合和策略模式。 link text
这比使用基于继承的行为灵活得多,因为它允许您在运行时通过根据需要替换新的Car类型进行更改。 |
![]() |
4
2
您可以使用 composition 。在您的示例中,Car对象可能包含另一个名为Drivetrain的对象。汽车的move()方法可以简单地调用其传动系统的drive()方法。传动系类反过来可能包含发动机、变速器、车轮等对象。如果你以这种方式构建你的类层次结构,你可以通过将更简单的部分的不同组合(即重用代码)组合起来,轻松创建以不同方式移动的汽车。 |
![]() |
5
2
为了使混合/组合更容易,请查看我的注释和注释处理器: http://code.google.com/p/javadude/wiki/Annotations 特别是mixins示例: http://code.google.com/p/javadude/wiki/AnnotationsMixinExample 请注意,如果被委托的接口/类型具有参数化方法(或方法上的参数化类型),则目前不起作用。我正在努力解决这个问题。.. |
![]() |
6
2
回答我自己的问题很有趣,但我发现了一件非常有趣的事情: Sather . 这是一种完全没有实现继承的编程语言!它知道接口(称为没有实现或封装数据的抽象类),接口可以相互继承(实际上它们甚至支持多重继承!),但一个类只能实现接口(抽象类,任意多),不能从另一个类继承。然而,它可以“包含”另一个类。这更像是一个委托概念。包含的类必须在类的构造函数中实例化,并在类被销毁时销毁。除非你覆盖它们的方法,否则你的类也会继承它们的接口,但不会继承它们的代码。相反,创建的方法只是将对方法的调用转发到所包含对象的同名方法。包含的对象和仅封装的对象之间的区别在于,你不必自己创建委托转发,它们也不是你可以传递的独立对象,它们是你的对象的一部分,与你的对象一起生灭(或者更严格地说:你的对象和所有包含的对象的内存是通过一个alloc调用创建的,同一个内存块,你只需要在构造函数调用中初始化它们,而当使用真正的委托时,每个对象都会引起自己的alloc调用,有自己的内存块,并且完全独立于你的对象)。 语言不是很美,但我喜欢它背后的想法:-) |
![]() |
7
1
面向对象语言不需要继承。 考虑Javascript,可以说它比Java更面向对象。没有类,只有对象。通过向对象添加现有方法来重用代码。Javascript对象本质上是一个名称到函数(和数据)的映射,其中映射的初始内容由原型建立,新条目可以动态添加到给定的实例中。 |
![]() |
8
0
你应该阅读设计模式。你会发现接口对于许多类型的有用设计模式至关重要。例如,抽象不同类型的网络协议将具有相同的接口(到调用它的软件),但由于每种协议的不同行为,代码重用很少。 因为一些算法在展示如何将编程的无数元素组合在一起以完成一些有用的任务方面令人大开眼界。设计模式对对象也有同样的作用。向您展示如何以一种执行有用任务的方式组合对象。 |
|
simply lemon · python上链表的添加方法 1 年前 |
|
Anonymous · 为什么在这个例子中self和类名的用法不同? 1 年前 |
![]() |
P N Singh · 在CPP Oops中调用对象而不创建它 1 年前 |
![]() |
Muthuraj · 如何创建一个通用工厂来创建某种类型的实例[重复] 1 年前 |
![]() |
Andy Votava · 从父类定义调用学生方法 1 年前 |