2017-10-25 6 views
3

Angenommen habe ich die folgende Schnittstelle und Implementierung:Wie klassenspezifischen Methoden ohne Instanceof zuzugreifen oder getClass

interface Weapon{ 
    int attack(); 
} 

public class Sword implements Weapon { 

    //Constructor, and Weapon interface implementation 
    //... 
    public void wipeBloodfromSword(){} 
} 


public class ChargeGun implements Weapon { 
    //Constructor, and Weapon interface implementation 
    //... 
    public void adjustlasersight(){} 
} 

und speichern sie wie folgt aus:

List<Weapon> weaponInventory = new ArrayList<Weapon>(); 
weaponInventory.add(new Sword()); 
weaponInventory.add(new ChargeGun()); 

Problem:

Da sie in der List<Weapon> gespeichert sind habe ich natürlich nur Zugriff auf die Methoden in derdeklariertinterface. Wenn downcasting und die Verwendung von instanceof/getClass() vermieden werden sollte, wie bekomme ich Zugriff auf die Klassenspezifischen Methoden wipeBloodfromSword() und adjustlasersight()?

Mögliche Lösung:

Da es Aktionen vor und nach dem Angriff Methode aufgerufen wird, kann ich meine Schnittstelle wie folgt neu schreiben:

interface Weapon{ 

    //Can reload a weapon, adjust a laser sight 
    //do anything to the weapon to prepare for an attack 
    void prepareWeapon(); 
    int attack(); 
    //Not sure of a more proper name, 
    //but you can wipe blood off sword or take off silencer 
    void postAttackActions(); 
} 

Während, ich bin in Kontrolle über dieses Hobby-Projekt, könnte ich in eine Situation geraten, wo ich nicht in der Lage bin, die interface zu ändern, während die interface umschreiben kann dieses spezifische Problem zu lösen, was soll ich tun, wenn ich die interface wie verlassen muss?

+0

"Was soll ich tun, wenn ..." ist keine gute Frage, die man auf SO stellen sollte. –

+1

Wenn Sie Ihre Schnittstelle nicht ändern können, müssen Sie entweder * instanceof oder reflection verwenden. Aber die richtige Antwort ist, deine Schnittstelle zu ändern. –

+0

Statische Klasse ist keine richtige Antwort ??? –

Antwort

2

Da Sie einen festen Satz von Klassen haben, können Sie das Besuchermuster verwenden könnte, die ohne explizite downcasts funktioniert.

class WeaponVisitor { 
    void visit(Sword aSword) { } 
    void visit(ChargeGun aGun) { } 
} 

// add accept method to your Weapon interface 
interface Weapon { 
    ... 
    void accept(Visitor v); 
} 

// then implement accept in your implementing classes 
class Sword { 
... 
    @Override 
    void accept(Visitor v) { 
     v.visit(this); // this is instanceof Sword so the right visit method will be picked 
    } 
} 

// lastly, extend Visitor and override the methods you are interested in 
class OnlySwordVisitor extends Visitor { 
    @Override void visit(Sword aSword) { 
     System.out.println("Found a sword!"); 
     aSword.wipeBloodfromSword(); 
    } 
} 
+0

Wunderbar, ich muss nicht 'downcasting',' instanceof' oder 'getClass()' –

+0

verwenden. Wenn du kannst, ändere das 'void accept (Visitor v) 'void akzeptieren (WeaponVisitor v);' OnlySwordVisitor muss '' Visitor' nicht erweitert werden, ich kann einfach den 'WeaponVisitor' verwenden, richtig? –

+0

ja, sicher. 'SwordVisitor' ist nur ein Beispiel für einen Besucher, mit dem man nur mit Schwertern handeln kann. Auch wenn du in die abstrakte Klasse "AbstractWeapon implements Weapon" wirfst, brauchst du nur "accept" in dieses zu implementieren, wenn alle konkreten Waffen es unterklassifizieren –

-1

können Sie geben Ihre Listenelemente zu Schwert oder ChargeGun werfen und rufen Sie dann die entsprechenden Methoden

((Sword) weaponInventory.get(0)).wipeBloodfromSword(); 
+0

Aber um zu werfen, hätte ich zuerst den Typ überprüft (mit 'instanceof 'oder' getClass() '). Es gibt keine Garantie dafür, dass das Schwert das erste Item im Inventar sein wird. –

Verwandte Themen