2016-05-01 4 views
2

У меня есть иерархия классов так:Java - расширение иерархии целого класса

abstract class BaseThing 
{ 
    public abstract void doSomething(); 
} 

class Thing1 extends BaseThing 
{ 
    @Override 
    public void doSomething() 
    { 
     doSomethingWithThing1(); 
    } 
} 

class Thing2 extends BaseThing 
{ 
    @Override 
    public void doSomething() 
    { 
     doSomethingWithThing2(); 
    } 
} 

// A dozen more classes that extend the BaseThing class. 

Мне нужно создать расширенную версию всего дерева. На Java нет множественного наследования, поэтому я создал его как:

interface BaseThingExt 
{ 
    public void doSomethingElse(); 
} 

class Thing1Ext extends Thing1 implements BaseThingExt 
{ 
    @Override 
    public void doSomethingElse() 
    { 
     doSomethingElseWithThing1(); 
    } 
} 

// All Thing.. classes are extended by ThingExt... classes 

Теперь вопрос. Где я могу поместить некоторые общие поля для всех классов ThingExt? Я не могу поместить их в базовый интерфейс, так как они станут final static. Я не могу сделать BaseThingExt абстрактным классом, поскольку Java не поддерживает множественное наследование. Я не могу поверить, что единственное решение - это повторить их десятки раз во всех классах ThingExt!

EDIT: Обратите внимание, что все классы ThingExt должны расширять свои классы Thing, а не только класс BaseThing, потому что в каждом производном классе есть некоторые особенности. Поэтому ответ @Hamdi Douss не будет работать.

+0

Почему вы не реализуете 'BaseThingExt' в' BaseThing' и не расширяете 'Thing1' и' Think2'. –

+0

@Shree Krishna: BaseThing и BaseThingExt живут в разных пакетах. Бывают ситуации, когда только BaseThing должен быть доступен клиентам. – Flot2011

+0

Можете ли вы создать абстрактный класс, который реализует интерфейс, включая ваши поля, с абстрактными методами getters/seters для реализации и расширения конкретных классов? –

ответ

7

Обычный трюк состоит в использовании композиции, а не наследованию:

interface BaseThingExt 
{ 
    public void doSomethingElse(); 
} 

class ConcreteImplementation implements BaseThing, BaseThingExt { 

    private final BaseThing thingDelegate; 
    private final BaseThingExt extDelegate; 

    public ConcreteImplementation(BaseThing thing, BaseThingExt ext) { 
     this.thingDelegate = thing; 
     this.extDelegate = ext; 
    } 


    @Override 
    public void doSomething() { 
     thingDelegate.doSomething(); 
    } 

    @Override 
    public void doSomethingElse() { 
     extDelegate.doSomethingElse(); 
    } 
} 
+0

Я, наконец, понял, что мне мешает об этом решении. Мне нужно было бы иметь 2 экземпляра, один из классов Thing и один из ThingExt для каждого объекта ConcreteImplementation, вместо того, чтобы иметь только один. Я прав, или я чего-то не хватает? – Flot2011

+0

Да. Идея заключается в том, что у вас есть иерархия классов Thing и иерархия классов ThingExt, и этот класс позволяет создать экземпляр обоих, используя любой член обеих иерархий. –

3

Я предлагаю, чтобы добавить супер класс AbstractBaseThingExt:

abstract class AbstractBaseThingExt implements BaseThingExt 
{ 
    private Object commonField; 
    public Object getCommonField(){} 
    public Object setCommonField(Object commonField){} 
} 

class ThingExt extends AbstractBaseThingExt 
{ 
    public ThingExt(BaseThing base) { 
     this.base = base; 
    } 

    public void doSomething() 
    { 
     this.base.doSomething(); 
    } 
} 

Класс ThingExt должен делегировать реализацию в base в случае необходимости.

+0

не будет работать. Thing1Ext должен расширять Thing1, а не BaseThing, здесь есть некоторые общие особенности. – Flot2011

+0

Получил это. В этом случае единственное решение, которое у вас есть, - это использовать композицию: 'class ThingExt extends AbstractBaseThingExt' с AbstractBaseThingExt - ваш абстрактный класс, который содержит общие поля. Тогда 'ThingExt' должен взять' BaseThing' в конструкторе. Редактирование моего ответа ... –

+0

@ Flot2011, ваше собственное предлагаемое решение делает именно это. 'ThingXExt расширяет ThingX', который расширяет BaseThing. Вы не можете удалить наследование «BaseThing» дальше по иерархии. – ChiefTwoPencils