Implementierung eines Interfaces erweitern

Heimchen

Mitglied
Hallo alle zusammen,
ich komme eigentlich von C, daher vermute ich mal, dass mein Thema eher in die Kategorie Anfänger gehört.
Ich schreibe ein Plugin für ein Tool und binde dafür die API von dem Tool ein. Die Methoden geben mir ein Interface auf Elemente des Tools zurück. Jetzt würde ich gerne einige der Methoden der Elemente erweitern und wollte dazu von der Interface-Klasse ableiten - da wusste ich aber noch nicht, dass es nur ein Interface ist. Die Klasse, die das Interface implementiert, ist nicht dokumentiert. Kann ich trotzdem irgendwie die Klasse erweitern?
Meine Alternative wäre, meine Methoden prozedural in meine eigene Klasse zu schreiben. Aber ich will ja objektorientiert.
Gruß,
Heimchen

PS: Das Original-Interface kann ich nicht bearbeiten.
 
Zuletzt bearbeitet:
Ich weiß zwar nicht genau was du da machen willst, aber Interfaces kann man erweitern:
Java:
interface Equality<T> {
  boolean equalTo(T o);
}
interface Ordering<T> extends Equality<T> {
  boolean lessThan(T o);
}
Natürlich kannst du auch Klassen ableiten (auch wenn du den Source-Code nicht besitzt), wenn sie die richtige Sichtbarkeit aufweisen und nicht final sind.
 
Der Name der Klasse ist mir leider nicht bekannt. Das Problem ist, dass mein erweitertes Interface ja auch gleich die Implementierung meiner Erweiterung enthalten müsste, weil es ja nach wie vor von der Klasse der API implementiert wird.
Vielleicht macht es das etwas deutlicher. IApi ist das Interface, was ich über die Api abfragen kann, um Elemente meines Tools zu bearbeiten:
Java:
IApi e = getElement();
e.apiMethod();

Ich möchte jetzt quasi sowas haben:
Java:
public interface IMyApi extends IApi {
  void myMethod() {
    return;
  }
}

IMyApi e = (IMyApi) getElement();
e.apiMethod();
e.myMethod();
 
Du könntest überlegen Kompositionen zu nutzen:

Code:
public interface IMyApi extends IApi { ... }

public class MyClass implements IMyApi {
    private IApi api;

    MyClass() {
        api = getElement();
    }

    @Override
    public void apiMethod() {
        api.apiMethod();
    }
}
 
Ist das jetzt ein XY Problem? Kannst du genau sagen was du machen willst? Denn so funktioniert das nicht.
Wenn getElement() eine IApi zurückgibt kannst du da nicht casten oder implementierst du getElement()?
 
Nein, ich implementiere nicht getElement(). Es sieht auch in echt so aus:
Java:
import externalToolApi;    // implements method "static IApi getElement();"
import IApi;

public class myClass {
  static void main(String[] args) {
    IApi e = externalToolApi.getElement();

    myClass.myMethod(e);
  }

  static void myMethod(IApi e) {
    // Tu irgendwas mit e
  }
}

Statt myMethod prozedural aufzurufen, würde ich gerne objektorientiert arbeiten. Probiert hab ich das:
Java:
import externalToolApi;    // implements method "static IApi getElement();"
import IApi;

public interface myApi extends IApi {
  void myMethod() {
    // Tu irgendwas mit this
  }
}

public class myClass {
  static void main(String[] args) {
    IMyApi e = externalToolApi.getElement();

    e.myMethod(e);
  }
}

Wenn mich nicht alles täuscht, ist das in C recht einfach wie beschrieben möglich, weil es keine expliziten Interfaces gibt. Da kann ein Interface auch eine Implementierung enthalten.
 
Wie schon @stg erwähnt hat würde ich Kompositionen nutzen. Das heißt das von getElement() zurück gegebene Objekt einfach in einem eigenen Klasse Wappen und die Klasse implementiert dein MyAPI Interface. Wobei der Name hier des Interfaces nix sagend ist...

Damit kannst du dann die Methode die du von der externen API nutzt weiter delegieren und deine eigenen Methode hinzufügen.

Ich glaube diese Idee wird auch im Buch Working with Legacy Code erwähnt. Damit bekommst du ein schönes Design da du die unterliegende Bibliothek komplett von deinem Code Abstract machst und so es ermöglichst einfach die Bibliothek aus zu tauschen.

Der Schlüssel ist dein eigenes Interface...
 
Copy Paste im Eifer des Gefechts. Richtig wäre folgendes:
Java:
import externalToolApi;   // implements method "static IApi getElement();"
import IApi;

public interface myApi extends IApi {
  void myMethod() {
    // Tu irgendwas mit this
  }
}

public class myClass {
  staticvoid main(String[] args){
    IMyApi e = externalToolApi.getElement();

    e.myMethod(e);
  }
}
 
Das mit der Composition hat den kelinen Haken, dass IApi so um die 50 Methoden hat. Die möcht ich eigentlich nicht alle von Hand wrappen müssen...
 
Was du hier nachzubauen versuchst sind Extension-Methods und werden in Java in dieser Form nicht unterstützt. Also ich würde wie @stg schon gesagt hat einen Wrapper um dieses Objekt bauen.

PS: Wo ist jetzt der Unterschied von den einem Codesnippet zu den anderen?
 
Die Frage ist brauchst du alle 50 Methode ? Oder reichen dir 3 für den Anfang und die anderen kommen dann im Laufe des Projektes.

Kannst ja auch zwei Interface machen, einmal das Wrapper Interface und dein Interface mit eigenen Methode, das vom Wrapper Interface erbt. Damit kannst du zwei Implementierungsklassen machen und hast den Code einwenig separiert.
 
PS: Wo ist jetzt der Unterschied von den einem Codesnippet zu den anderen?
Da waren ein paar kleine Verschreiber, z.B. IMyApi vs. myApi, etc.

Das mit dem Wrapper scheint zu gehen. Das mit dem Delegieren in Eclipse kannte ich noch nicht.
Bekomme ich das denn auch so hin, dass sich das Handling mit meinem Wrapper-Interface nicht von dem der ursprünglichen API-Interfaces unterscheidet? In etwa so:
Java:
IApi1 eins = externalToolApi.getElement1();
eins.foo();

IApi2 zwei = externalToolApi.getElement2();
zwei.baa();

IMyApi drei = externalToolApi.getElement3();
drei.myFooBaa();
 
Ich meinte eigentlich so:

Interfaces:
Java:
public interface APIWrapper {
  // Methoden die du von IApi wrappen willst
  void methodeA();
  // ....
}

public interface MyAPI extends APIWrapper {
  // Deine Methoden die du selbst implementierst
  void myMethodeA();
  //...
}

Implementierung:
Java:
public class APIWrapperImpl implements APIWrapper {
  private IApi api = null;

  APIWrapperImpl(IApi api) {
    this.api = api;
  }

  public void methodeA () {
    this.api.methodeA ();
  }
}

public class MyAPIImpl extends APIWrapperImpl implements MyAPI {

  public APIWrapperImpl (IApi api) {
    super(api);
  }

  public void myMethodeA (){
    //...
  }
}
Factory:

Java:
public class MyAPIFactory {
  private MyAPIFactory (){}

  public static MyAPI create (IApi api) {
    return new MyAPIImpl(api);
  }
}

Usage:
Java:
IApi api = externalToolApi.getElement();
MyAPI myApi = MyAPIFactory.create (api);

myApi.methodeA ();
myApi.myMethodeA ();

Und dann kannst du alles noch mit Unittests testen ohne die unterliegende API zu nutzen.
 

Neue Themen


Zurück
Oben