有什么组合不能实现继承可以吗? [英] Is there anything composition cannot accomplish that inheritance can?

查看:14
本文介绍了有什么组合不能实现继承可以吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

组合和继承.

我知道它们都是在适当时选择的工具,并且上下文对于在组合和继承之间进行选择非常重要.然而,关于每种情况的适当上下文的讨论通常有点模糊.这让我开始考虑继承和多态是传统 OOP 的不同方面有多么明显.

I am aware that they are both tools to be chosen when appropriate, and context is very important in choosing between composition and inheritance. However, the discussion about the appropriate context for each is usually a little fuzzy; this has me beginning to consider just how distinctly inheritance and polymorphism are separate aspects of traditional OOP.

多态性允许人们同样指定is-a"关系以及继承.特别是,从基类继承隐含地在该类与其子类之间创建了多态关系.然而,虽然多态可以使用纯接口来实现,但继承通过同时传递实现细节使多态关系复杂化.这样一来,继承就与纯多态截然不同了.

Polymorphism allows one to specify "is-a" relationships equally as well as inheritance. Particularly, inheriting from a base class implicitly creates a polymorphic relationship between that class and its subclasses. However, whereas polymorphism can be implemented using pure interfaces, inheritance complicates the polymorphic relationship by simultaneously transferring implementation details. In this way, inheritance is quite distinct from pure polymorphism.

作为一种工具,继承服务于程序员的方式不同于多态性(通过纯接口),它简化了实现的重用在琐碎的情况下.然而,在大多数情况下,超类的实现细节与子类的要求存在微妙的冲突.这就是我们有覆盖"和成员隐藏"的原因.在这些情况下,继承提供的实现重用是通过验证状态更改和跨级联代码级别的执行路径的额外努力来购买的:子类的完整扁平化"实现细节分布在多个类之间,这通常意味着多个文件,其中只有部分适用于所讨论的子类.在处理继承时,查看该层次结构是绝对必要的,因为如果不查看超类的代码,就无法知道哪些未覆盖的细节会影响您的状态或转移您的执行.

As a tool, inheritance serves programmers differently than polymorphism (through pure interfaces) by simplifying implementation re-use in trivial cases. In the majority of cases, however, the implementation details of a superclass subtly conflict with the requirements of a subclass. This is why we have "overrides" and "member hiding". In these cases, the implementation re-use offered by inheritance is purchased with the added effort of verifying state changes and execution paths across cascading levels of code: the complete "flattened" implementation details of the subclass are spread between multiple classes, which usually means multiple files, of which only portions apply to the subclass in question. Looking through that hierarchy is absolutely necessary when dealing with inheritance, because without looking at the code of the superclass, there is no way to know what un-overidden details are monkeying with your state or diverting your execution.

相比之下,组合的独占使用保证您将看到哪些状态可以被显式实例化的对象修改,这些对象的方法由您自行决定调用.仍然没有实现真正扁平化的实现(实际上甚至是不可取的,因为结构化编程的好处是实现细节的封装和抽象)但是您仍然可以重用代码,并且您只需要查看一个地方当代码出现异常时.

In comparison, exclusive use of composition guarantees you will see what state can be modified by explicitly instantiated objects whose methods are invoked at your discretion. Truly flattened implementation is still not achieved (and actually isn't even desirable, since the benefit of structured programming is the encapsulation and abstraction of implementation details) but you still get your code-reuse, and you will only have to look in one place when the code misbehaves.

为了在实践中测试这些想法,避免传统的继承以结合纯基于接口的多态性和对象组合,我想知道,

With the goal of testing these ideas in practice, eschewing traditional inheritance for a combination of pure interface-based polymorphism and object composition, I am wondering,

有什么对象组合和接口无法完成继承可以做到的事情吗?

Is there anything object composition and interfaces cannot accomplish that inheritance can?

编辑

在迄今为止的回复中,ewernli 认为没有一种技术可用于技术专长,而另一种则不然;他后来提到了每种技术所固有的不同模式和设计方法.这是有道理的.但是,该建议使我通过询问排他使用组合和接口来代替传统继承是否会禁止使用任何主要设计模式来完善我的问题?如果是这样,是否有在我的情况下使用的等效模式?

In the responses so far, ewernli believes there are no technical feats available for one technique but not the other; he later mentions how different patterns and design approaches are inherent to each technique. This stands to reason. However, the suggestion leads me to refine my question by asking whether exclusive use of composition and interfaces in lieu of traditional inheritance would prohibit the use of any major design patterns? And if so, aren't there equivalent patterns for use in my situation?

推荐答案

从技术上讲,所有可以通过继承实现的东西也可以通过委托来实现.所以答案是不".

Technically everything that can be realized with inheritance can be realized with delegation as well. So the answer would be "no".

将继承转化为委托

假设我们有以下通过继承实现的类:

Let's say we have the following classes implemented with inheritance:

public class A {
    String a = "A";
    void doSomething() { .... }
    void getDisplayName() {  return a }
    void printName { System.out.println( this.getDisplayName() };   
}

public class B extends A {
    String b = "B";
    void getDisplayName() {  return a + " " + b; }
    void doSomething() { super.doSomething() ; ... }    
}

这些东西很好用,在 B 的实例上调用 printName 将在控制台中打印 "A B".

The stuff works nicely, and calling printName on an instance of B will print "A B" in the console.

现在,如果我们用委托重写它,我们会得到:

Now, if we rewrite that with delegation, we get:

public class A {
    String a = "A";
    void doSomething() { .... }
    void getDisplayName() {  return a }
    void printName { System.out.println( this.getName() };  
}

public class B  {
    String b = "B";
    A delegate = new A();
    void getDisplayName() {  return delegate.a + " " + b; }
    void doSomething() { delegate.doSomething() ; ... } 
    void printName() { delegate.printName() ; ... }
}

我们需要在 B 中定义 printName 并在实例化 B 时创建委托.对 doSomething 的调用将以与继承类似的方式工作.但是对 printName 的调用将在控制台中打印 "A".实际上,通过委托,我们失去了this"绑定到对象实例和能够调用已被覆盖的方法的基本方法的强大概念.

We need to define printName in B and also to create the delegate when B is instantiated. A call to doSomething will work in a similar way as with inheritance. But a call to printName will print "A" in the console. Indeed with delegation, we lost the powerful concept of "this" being bound to the object instance and base methods being able to call methods that have be override.

这可以在支持纯委托的语言中解决.使用纯委托,委托中的this"仍将引用 B 的实例.这意味着 this.getName() 将从 B 类开始方法分派.我们实现与继承相同.这是 prototype-based 语言中使用的机制,例如 Self 具有委托具有内置功能(您可以阅读 这里继承如何在 Self 中工作).

This can be solved in the language supports pure delegation. With pure delegation, "this" in the delegate will still reference the instance of B. Which means that this.getName() will starts the method dispatch from class B. We achieve the the same as with inheritance. This is the mechanism used in prototype-based language such as Self which have delegation has a built-in feature (You can read here how inheritance works in Self).

但是 Java 没有纯委托.什么时候卡住了?不,真的,我们仍然可以自己做更多的努力:

But Java doesn't have pure delegation. Are when then stuck? No really, we can still do that ourselves with some more effort:

public class A implements AInterface {
    String a = "A";
    AInterface owner; // replace "this"
    A ( AInterface o ) { owner = o }
    void doSomething() { .... }
    void getDisplayName() {  return a }
    void printName { System.out.println( owner.getName() }; 
}

public class B  implements AInterface {
    String b = "B";
    A delegate = new A( this );
    void getDisplayName() {  return delegate.a + " " + b; }
    void doSomething() { delegate.doSomething() ; ... } 
    void printName() { delegate.printName() ; ... }
}

我们基本上是在重新实现内置继承提供的功能.是否有意义?不完全是.但它说明继承总是可以转换为委托.

We are basically re-implementing what the built-in inheritance provides. Does it make sense? No really. But it illustrates that inheritance can always be converted to delegation.

讨论

继承的特点是基类可以调用在子类中被覆盖的方法.例如,这就是 模板模式的本质.这样的事情不能通过委派轻松完成.另一方面,这正是使继承难以使用的原因.理解多态调度发生在哪里以及如果方法被覆盖会产生什么影响,需要精神上的扭曲.

Inheritance is characterized by the fact that a base class can call a method that is overridden in a sub class. This is for instance the essence of the template pattern. Such things can not be done easily with delegation. On the other hand, this is exactly what makes inheritance hard to use. It require a mental twist to understand where polymorphic dispatch happen and what is the effect if methods are overridden.

有一些关于继承的已知陷阱以及它可能在设计中引入的脆弱性.特别是如果类层次结构不断发展.hashCode 中的 equality 也可能存在一些问题如果使用继承,则 equals.但另一方面,它仍然是解决一些问题的一种非常优雅的方式.

There are some known pitfalls about inheritance and the fragility it may introduce in the design. Especially if the class hierarchy evolves. There can also be some issues with equality in hashCode and equals if inheritance is used. But on the other side, it's still a very elegant way to solve some problems.

此外,即使继承可以用委托代替,您也可以争辩说它们仍然实现不同的目的并相互补充——它们没有传达相同的意图技术等价.

Also, even if inheritance can be replaced with delegation, one you can argue that they still achieve different purpose and complement each other -- they don't convey the same intention which is not captured by pure technical equivalence.

(我的理论是,当有人开始做 OO 时,我们很容易过度使用继承,因为它被认为是语言的一个特性.然后我们学习委托,它是模式/方法,我们学会也喜欢它.一段时间后,我们在两者之间找到了平衡,并发展出一种直觉,在哪种情况下哪个更好.好吧,正如您所看到的,我仍然喜欢两者,并且两者都值得谨慎使用正在介绍中.)

(My theory is that when somebody starts doing OO, we are tempted to over-use inheritance because it's perceive like a feature of the language. Then we learn delegation which is pattern/approach and we learn to like it as well. After some time, we find a balance between both and develop of sense of intuition of which one is better in which case. Well, as you can see, I still like both, and both deserve some caution before being introduced.)

一些文献

继承和委托是增量的替代方法定义和分享.它有普遍认为,代表团提供了更强大的模型.这论文证明有一个自然"的继承模式捕获所有属性代表团.独立地,确定能力的限制获取继承的委托是证明了.最后,一个新的框架这充分体现了两个代表团并概述了继承,还有一些这种混合的后果模型进行了探索.

Inheritance and delegation are alternate methods for incremental definition and sharing. It has commonly been believed that delegation provides a more powerful model. This paper demonstrates that there is a "natural" model of inheritance which captures all of the properties of delegation. Independently, certain constraints on the ability of delegation to capture inheritance are demonstrated. Finally, a new framework which fully captures both delegation and inheritance is outlined, and some of the ramifications of this hybrid model are explored.

  • 关于继承的概念

    其中一个最有趣的 - 并且在同时也是最有问题的——面向对象编程是遗产.继承很常见被视为特征区分面向对象其他现代编程编程范式,但研究人员很少就其含义和用法达成一致.[...]

    One of the most intriguing—and at the same time most problematic—notions in object-oriented programing is inheritance. Inheritance is commonly regarded as the feature that distinguishes object-oriented programming from other modern programming paradigms, but researchers rarely agree on its meaning and usage. [...]

    • 系统地将继承重构为 java 中的委托
    • 由于类的强耦合和不需要的类成员的激增导致通过继承,使用组合和委托的建议变得司空见惯.文献中相应重构的介绍可能会让人相信这种转变是一项直截了当的工作.[...]

      Because of the strong coupling of classes and the proliferation of unneeded class members induced by inheritance, the suggestion to use composition and delegation instead has become commonplace. The presentation of a corresponding refactoring in the literature may lead one to believe that such a transformation is a straightforward undertaking. [...]

      这篇关于有什么组合不能实现继承可以吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆