简体   繁体   English

Python中的多重继承; 用Java怎么做?

[英]Multiple inheritance in Python; how to do so in Java?

I'm porting some Python code to Java, and I am having trouble dealing with the following problem: 我正在将一些Python代码移植到Java,但无法处理以下问题:

I have some classes which need to have abilities A, B, or C. Class 1 needs ability A, class 2 needs A, B and C, and class 3 needs B and C. Most importantly, I want to easily be able to change what class can have what ability in the future. 我有一些需要具备能力A,B或C的课程。第一类需要能力A,第二类需要A,B和C,第三类需要B和C。最重要的是,我希望能够轻松地进行更改什么班级将来会有什么能力。

I solved this problem pretty easily with multiple inheritance in Python. 我使用Python中的多重继承非常轻松地解决了这个问题。 I'm trying to figure out the best way to do it in Java, but I can't come up with as good of a solution. 我正在尝试找出用Java做到这一点的最佳方法,但是我无法提供一个好的解决方案。 I know multiple inheritance is frowned-upon, so I'd appreciate being taught a better way. 我知道多重继承是一种皱眉,所以我很高兴被教给一个更好的方法。

Thanks! 谢谢!

Multiple-inheritance ain't frowned upon. 多重继承不会被拒绝。 What is frowned upon is "implementation inheritance" (also known as "code reuse"), because it leads to the unsolvable "diamond problem". 令人不满意的是“实现继承”(也称为“代码重用”),因为它导致了无法解决的“钻石问题”。 And because, well, code-reuse really hasn't much to do with OO. 而且因为代码重用确实与OO没有太大关系。

What you want to do can be solved using multiple inheritance (and, say, delegation if you need to do "code reuse"). 可以使用多重继承(例如,如果需要进行“代码重用”,则委托)来解决您想做的事情。

interface A {

    void move();

}

interface B {

    void eat();

}

interface C {

    void think();

}

class One implements A { ... }

class Two implements B { ... }

class Three implements B, C { ... }

Any OOA/OOD using multiple inheritance can be trivially translated to Java. 任何使用多重继承的OOA / OOD都可以轻松地转换为Java。 The part where you say that you need to change the "ability" all the time is a bit scary: if, say, a Car can move() , why would it suddenly need to be able to think() ? 您说一直需要更改“功能”的部分有点吓人:如果说一辆Car可以move() ,为什么突然需要它能够think()呢?

It depends on your actual use case, but have you already considered decorators? 这取决于您的实际用例,但是您是否已经考虑过装饰器?

http://en.wikipedia.org/wiki/Decorator_pattern http://en.wikipedia.org/wiki/Decorator_pattern

You can use AspectJ's mixin syntax fairly easily to emulate multiple inheritance (and at compile time too). 您可以相当容易地使用AspectJ的mixin语法来模拟多重继承(也可以在编译时)。 First, declare an interface for the functionality you want to mixin: 首先,为要混合的功能声明一个接口:

public interface A{
    String getSomethingForA();
}

then define an annotation which you can use to signify that you want the mixin applied to a given class: 然后定义一个注释,您可以使用该注释来表示您希望将mixin应用于给定的类:

public @interface WithA {}

then add the annotation to the class you want to use: 然后将注释添加到您要使用的类中:

@WithA
public class MyClass {}

then, to actually add some functionality: 然后,实际添加一些功能:

@Aspect
public class MixinA {
    public static class AImpl implements A{
        public String getSomethingForA() {
            return "it worked!";
        } 
    }

    @DeclareMixin("@WithA *")
    public static A get() {
        return new AImpl();
    }
}

You'll need to use the aspectj jars and run the aspects as part of your compile process, but this lets you create truly modularized functionality and then forcibly merge it into your classes later. 您需要使用aspectj jars并在编译过程中运行方面,但这可以让您创建真正的模块化功能,然后在以后将其强制合并到您的类中。 To access your class with the new functionality, do the following: 要使用新功能访问您的课程,请执行以下操作:

MyClass obj = new MyClass();
((A)obj).getSomethingForA();

You can apply the same annotation to another class and cast it as well: 您可以将相同的注释应用于另一个类并将其强制转换为:

@WithA
@WithB //let's pretend we created this with some other functionality
public class AnotherClass {}

AnotherClass anotherObj = new AnotherClass();
((A)anotherObj).getSomethingForA();
((B)anotherObj).andSetSomethingElseForB("something else");

Multiple inheritance is almost always a bad idea, as its effects can usually be achieved through other mechanisms. 多重继承几乎总是一个坏主意,因为它的影响通常可以通过其他机制来实现。 Based upon your description of the problem, it sounds like you want to 根据您对问题的描述,听起来您想

  1. Use interfaces to define behavior (public interface A) in this scenario, each behavior should probably have its own interface. 在这种情况下,请使用接口定义行为(公共接口A),每个行为可能都应具有自己的接口。

If 2 behaviors are tightly coupled (say A & B), define an interface that implements those two atomic interfaces (public interface CombinedAandB extends A, B) 如果2个行为紧密耦合(例如A和B),则定义一个实现这两个原子接口的接口(公共接口CombinedAandB扩展A,B)

  1. Define an abstract base class that implements the interface to provide default implementations for behaviors 定义一个实现接口的抽象基类,以提供行为的默认实现

     public abstract class BaseAB implements A, B { @Override public void A() { add(0,1); } 
      @Override public void B() {add(1,0); } private void add(int a, int b) //it doesn't return. no soup for you. { a + b; //If you know why this is wrong, high five yourself. } 
    \n\n} }\n
  2. Define a concrete class that extends the abstract base class, implements another interface, and provides its own behavior. 定义一个扩展抽象基类,实现另一个接口并提供其自己行为的具体类。

    public class IDoABAndC extends BaseAB implements C { //stuff, etc } 公共类IDoABAndC扩展BaseAB实现C {//东西等}

您可以在接口中定义功能并在您的类中实现它们。

In java you don't have multiple inheritance, instead you can implement multiple interfaces. 在Java中,您没有多重继承,而是可以实现多个接口。

So your class 1 will implement interface A and B. Class 2 will implement interface A, B and C. Class 3 will implement B and C. 因此,您的第1类将实现接口A和B。第2类将实现接口A,B和C。第3类将实现B和C。

If what you need is interface inheritance, then as mentioned before, you can always implement multiple interfaces. 如果您需要接口继承,那么如前所述,您可以始终实现多个接口。

If you're looking for implementation inheritance, you're somewhat out of luck. 如果您正在寻找实现继承,那么您会有些运气。 The best solution is probably to use delegation — replace the extra superclasses with fields, and implement methods that just delegate to those fields. 最好的解决方案可能是使用委托-用字段替换多余的超类,并实现只委托给这些字段的方法。 It does require writing a lot of repetitive delegation methods, but it's rather unavoidable in Java (without resorting to AspectJ or other bytecode-munging tricks; careful, this way madness lies …). 它确实需要编写许多重复的委派方法,但是在Java中这是不可避免的(无需求助于AspectJ或其他字节码修改技巧;要小心,这种疯狂的方式在于……)。

This is a bit tangential, but you can have python code running in Java via Jython (http://www.jython.org/). 这有点切线,但是您可以通过Jython(http://www.jython.org/)在Java中运行python代码。 This addresses the porting to Java part, not the solving multiple inheritance part (I think you need to determine which is relevant) 这解决了移植到Java部分,而不是解决多重继承问题(我认为您需要确定哪个是相关的)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM