多重继承,无多重继承,无代码重复
本文关键字:多重继承 代码 | 更新日期: 2023-09-27 18:35:24
我有一个理论问题,关于如何在不允许多重继承的语言中处理以下情况。
想象一下,我有一个基类Foo,我希望从中创建三个子类:
- 类栏继承了Foo并实现了功能"A"
- 类 Baz 继承 Foo 并实现功能"B"
- 类 Qux 继承 Foo 并实现功能 "A" 和 "B"
想象一下,实现功能"A"和"B"的代码总是相同的。有没有办法只为"A"和"B"编写一次代码,然后让适当的类应用(或"继承")它?
好吧,我能看到你在 C#/Java 中实现这一点的唯一方法是通过组合。考虑一下:
class Foo {
}
interface A {
public void a();
}
interface B {
public void b();
}
class ImplA implements A {
@Override
public void a() {
System.out.println("a");
}
}
class ImplB implements B {
@Override
public void b() {
System.out.println("b");
}
}
class Bar extends Foo {
A a = new ImplA();
public void a() {
a.a();
}
}
class Baz extends Foo {
B b = new ImplB();
public void b() {
b.b();
}
}
class Qux extends Foo {
A a = new ImplA();
B b = new ImplB();
public void b() {
b.b();
}
public void a() {
a.a();
}
}
现在Qux
既具有通过正常继承Foo
的功能,又具有通过组合实现A
和B
的功能。
更通用的术语是Mixin。有些语言提供开箱即用的支持,例如 Scala 和 D。但是,有多种方法可以在其他语言中实现相同的结果。
在 C# 中创建伪 mixin 的一种方法是使用空接口并为方法提供扩展方法。
interface A { }
static class AMixin {
public static void aFunc(this A inst) {
... //implementation to work for all A.
}
}
interface B { }
static class BMixin {
public static void bFunc(this B inst) {
...
}
}
class Qux : Foo, A, B {
...
}
这
在提供特征的语言中是可以实现的(这里:scala):
class Foo {
def fooM() {}
}
trait A {
def aFunc() {}
}
trait B {
def bFunc() {}
}
class Bar extends Foo with A {}
class Baz extends Foo with B {}
class Qux extends Foo with A with B {}
因为 Scala 运行在 Java 之上(既没有多重继承也没有特征),所以它被翻译成这样的东西(简化) - 这可能是如何在 Java/C# 中手动实现它的提示:
class Foo {
}
interface A {
void aFunc();
}
interface B {
void bFunc();
}
class Bar extends Foo implements A {
public void aFunc() {
$A.aFunc();
}
}
class Baz extends Foo implements B {
public void bFunc() {
$B.bFunc();
}
}
class Qux extends Foo implements A, B {
public void aFunc() {
$A.aFunc();
}
public void bFunc() {
$B.bFunc();
}
}
class $A {
public static void aFunc() {}
}
class $B {
public static void bFunc() {}
}
有几种方法可以做这样的事情。更具体地说,如果我们暂时放弃继承方面,有一些方法可以将相同的功能单元引入不同的类,而只编写一次单元。
好的,我喜欢AOP框架,它们存在于许多语言中(C#和Java有几个)。AOP框架基本上允许您在整个继承结构中将自包含功能添加到不同的类中。
对于C#,你有PostSharp,对于Java,你有AspectJ,等等。
许多AOP框架允许在不使用继承的情况下"劫持"或"覆盖"方法调用。