简体   繁体   中英

Efficient way to share the same interface implementation between two or more classes

Suppose a part of a class library with the following hierarchy:

class Super {
  void doSomething() {
    System.out.println("Super is doing something");
  }
}

class SubOne extends Super {
  @Override
  void doSomething() {
    System.out.println("SubOne is doing something");
  }

  void doSomethingElse() {
    System.out.println("SubOne is doing something else");
  }
}

class SubTwo extends Super {
  @Override
  void doSomething() {
    System.out.println("SubTwo is doing something");
  }

  void doSomethingDifferent() {
    System.out.println("SubTwo is doing something different");
  }
}

Now someone defines a new interface offering behavior that is relevant to both SubOne and SubTwo classes:

interface NewBehavior {
  void doSomethingNew();
}

As far as I can tell, if we can't modify the source code for Super, SubOne and SubTwo, there are two ways to define new versions of SubOne and SubTwo that implement NewBehavior.

One is to implement NewBehavior in a subclass of Super and then create new versions of SubOne and SubTwo by subclassing the new version of Super (and possibly wrapping SubOne and SubTwo objects):

class ExtendingSuperNewBehavior extends Super
implements NewBehavior {
  @Override
  public void doSomethingNew() {
    System.out.println("ExtendingSuperNewBehavior is doing something new");
  }  
}

class ExtendingSuperSubOneNewBehavior extends ExtendingSuperNewBehavior {
  // Here we need to either wrap SubOne or redefine doSomethingElse()
  // with the same implementation.
  // SubOne mSubOne = new SubOne();
  // void doSomethingElse() {
  //   mSubOne.doSomethingElse();
  // }

   void doSomethingElse() {
    System.out.println("SubOne is doing something else");
  }
} 

class ExtendingSuperSubTwoNewBehavior extends ExtendingSuperNewBehavior {
  // Here we need to either wrap SubTwo or redefine doSomethingDifferent()
  // with the same implementation.
  // SubTwo mSubTwo = new SubTwo();
  // void doSomethingDifferent() {
  //   mSubTwo.doSomethingDifferent();
  // }

   void doSomethingDifferent() {
    System.out.println("SubTwo is doing something different");
  }
} 

The other is to define a class that implements NewBehavior and wrap an instance in each of the new versions of SubOne and SubTwo:

class NewBehaviorImpl implements NewBehavior {
  @Override
  public void doSomethingNew() {
    System.out.println("NewBehaviorImpl is doing something new");
  }
}

class ImplementingSubOne extends SubOne 
implements NewBehavior {
  NewBehavior mNewBehavior = new NewBehaviorImpl();

  public void doSomethingNew() {
    mNewBehavior.doSomethingNew();
  }
}

class ImplementingSubTwo extends SubTwo 
implements NewBehavior {
  NewBehavior mNewBehavior = new NewBehaviorImpl();

  public void doSomethingNew() {
    mNewBehavior.doSomethingNew();
  }
}

Obviously, both of these methods work, but if SubOne and/or SubTwo expose a large interface (as library classes usually do) there is a lot of method forwarding to be done no matter which method is chosen.

Can anyone think of a way to reuse the same interface implementation that would avoid code forwarding? It would help a lot.

Consider using an AOP (Aspect Oriented Programming) library like AspectJ. One of the things you can do with AOP is introduce additional attributes or methods to existing classes. In your example you would add the new method transparently to the SubOne and SubTwo subclasses without ever touching these classes. An AOP application basically will use proxies to your original classes in a transparent way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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