2016-07-22 3 views
3

Nicht sicher, ob dies möglich ist, aber ich habe einen Fall, in dem zwei Schnittstellen die gleiche Methode haben. Dies sind Schnittstellen, die gegeben sind, also kann ich sie nicht ändern.Java - Generalisieren Sie verschiedene Klassen, ähnliche Methoden (ohne die Unterklassen zu ändern?)

Da Schnittstellen

interface SomeGivenService { 
    boolean authenticate(String username, String password); 
    Object someSpecialMethod(Object param); 
} 

interface AnotherGivenService { 
    boolean authenticate(String username, String password); 
    String aGreatMethod(); 
    String sayHello(); 
} 

diesen Dienst zu verbrauchen, habe ich eine Klasse und tat, falls etwas Handhabung dieser Dienst einen Fehler wirft.

class SomeGivenServiceConsumer { 

    SomeGivenService a; 

    public SomeGivenServiceConsumer(SomeGivenService a) { 
     this.a = a; 
    } 

    public authenticate(MyUserPassBean bean) { 
     try { 
      a.authenticate(bean.username, bean.password); 
     } catch (Exception e) { 
      throw new MyException(); 
     } 
     ... 
    } 
} 

class AnotherGivenServiceConsumer { 

    AnotherGivenService a; 

    public AnotherGivenServiceConsumer(AnotherGivenService a) { 
     this.a = a; 
    } 

    public authenticate(MyUserPassBean bean) { 
     try { 
      a.authenticate(bean.username, bean.password); 
     } catch (Exception e) { 
      throw new MyException(); 
     } 
     ... 
    } 
} 

Ist es möglich, diese Codeverdoppelung bei meinen Kunden zu vermeiden? Ich werde wahrscheinlich viele von ihnen haben und diesen doppelten Code vermeiden wollen. Ich dachte ursprünglich daran, meinen Consumer zu ändern, um eine Schnittstelle zu erhalten, die diese Authentifizierung implementiert, aber wie ich die gegebenen Schnittstellen nicht ändern kann, nicht sicher, ob das überhaupt möglich ist.

Ist es möglich, eine "generische Schnittstelle, die eine Methode hat?" oder ein Designmuster verwenden? Irgendwelche Ideen? Was ich versuche:

class AnotherGivenServiceConsumer { 

    AnotherGivenService a; 
    GivenServiceAuthenticable b; 

    public AnotherGivenServiceConsumer(AnotherGivenService a, 
             GivenServiceAuthenticable b) { 
     this.a = a; 
     this.b = b; 
    } 

    public authenticate(MyUserPassBean bean) throws MyException { 
     return b.authenticate(bean.username, bean.password); 
    } 
} 

interface GivenServiceAuthenticable<T> { 
    boolean authenticate(T givenService, MyUserPassBean bean); 
} 

class GivenServiceAuthenticableImpl<T> implements GivenServiceAuthenticable<T> { 
    boolean authenticate(T givenService, MyUserPassBean bean) { 
     try { 
      //this won't compile as it's a generic class.. 
      t.authenticate(bean.username, bean.password); 
     } catch (Exception e) { 
      throw new MyException(); 
     } 
     ... 
    } 
} 

Anderes Problem ist, wie dieses Objekt instanziieren, wenn ich es nicht meine neue Objekte ändern kann, implementieren?

+0

In Ihren 'authenticate' Methoden fehlt ein Rückgabetyp. – shmosel

+0

Haben Sie viele dieser Dienstleistungen oder nur eine Menge Verbraucher? – shmosel

+0

Haben alle Klassen, die die angegebenen Schnittstellen implementieren, die gleiche Logik für die Authentifizierung? Wenn ja, können Sie einfach eine neue "Schnittstelle" einführen, die die angegebenen Schnittstellen "erweitert" und Ihre "Consumer" diese Schnittstelle mit einer einzigen Definition für die Methode "authenticate (user, password)" implementieren lässt. – CKing

Antwort

1

können Sie die template pattern verwenden, um die gemeinsame Funktionalität in einer Basisklasse zu implementieren, während die einzelnen unterschiedlichen Linie delegieren zu Unterklassen:

abstract class ConsumerBase { 
    public void authenticate(MyUserPassBean bean) { 
     try { 
      authenticate(bean.username, bean.password); 
     } catch (Exception e) { 
      throw new MyException(); 
     } 
     //... 
    } 

    protected abstract boolean authenticate(String username, String password); 
} 

class SomeGivenServiceConsumer extends ConsumerBase { 

    SomeGivenService a; 

    public SomeGivenServiceConsumer(SomeGivenService a) { 
     this.a = a; 
    } 

    @Override 
    protected boolean authenticate(String username, String password) { 
     return a.authenticate(username, password); 
    } 
} 

class AnotherGivenServiceConsumer extends ConsumerBase { 

    AnotherGivenService a; 

    public AnotherGivenServiceConsumer(AnotherGivenService a) { 
     this.a = a; 
    } 

    @Override 
    protected boolean authenticate(String username, String password) { 
     return a.authenticate(username, password); 
    } 
} 
+0

Sie haben vergessen, von 'ConsumerBase' zu ​​verlängern; außerdem würde dies nur dann Sinn ergeben, wenn Implementierungen von "GivenService" und "AnotherGivenService" unterschiedliche Möglichkeiten/Logik haben, um einen Benutzer zu authentifizieren. Wenn sie genau denselben Code/dieselbe Logik haben, um einen Benutzer zu authentifizieren, wäre dies ein Overkill. – CKing

+0

humm, das macht Sinn @shmosel .. das ist, was ich suche! Vielen Dank!! CKing, sie haben _fast_ die gleiche Logik ..Die einzige Sache, die sich ändert, ist, dass jeder 'Consumer' das' authenticate' von einem spezifischen Objekt aufruft. Also glaube ich, dass der einzige Weg, dies zu erreichen, darin besteht, diese 'abstrakte' Methode zu benutzen. Danke !! –

0

Was Sie tun müssen, ist die Vererbung zu verwenden. Dann beschäftigen sich mit dem Fehler in der übergeordneten Klasse dh

class SomeGivenServiceConsumer { 

     SomeGivenService a; 
     AnotherGivenService b; 

     public SomeGivenServiceConsumer(SomeGivenService a) { 
      this.a = a; 
      try{ 
      authenticate(MyUserPassBean); 
      }catch (Exception e) { 
      System.out.println("Thrown exception has been caught : "+e.getMessage()); 
      } 
     } 

     public authenticate(MyUserPassBean bean) throws MyException { 
       //your implementation here 
     } 
    }  
    class AnotherGivenServiceConsumer extends SomeGivenServiceConsumer{ 

     public AnotherGivenServiceConsumer(AnotherGivenService b) { 
      super(someGivenService);//construct superclass 
      authenticate(MyUserPassBean);//call subclass authenticate method 
     } 

     @override 
     public authenticate(MyUserPassBean bean) throws MyException { 
       super.authenticate(MyUserPassBean);//call superclass method 
       //your implementation here 

     } 
    } 

dann bauen Sie die Unterklasse:

public static void main(String[] args) { 
    new AnotherGivenServiceConsumer(AnotherGivenService); 
} 
+0

'AnotherGivenServiceConsumer' kann' SomeGivenServiceConsumer' nicht erweitern, da sie neben der Authentifizierung verschiedene Methoden haben. Aber wenn Sie einen 'BaseConsumer' meinen, ist Ihre Idee ähnlich wie die vorgeschlagene shmosel .. außer ich würde seine bevorzugen, da ich immer noch nicht ' t müssen "authentifizieren" auf dem Konstruktor aufrufen .. aber vielen Dank für Ihre Hilfe! –

Verwandte Themen