基于依赖倒置原则,如何访问子类独有的非接口方法?
问题分析与解决方案
问题背景
现有代码结构中:
Weapon接口定义通用方法A()Sword、Bow实现Weapon,分别拥有独有方法B()、C()BattleService依赖Weapon接口,仅能调用通用方法A(),无法访问子类独有方法
需要在遵循依赖倒置原则(高层模块依赖抽象,而非具体实现)的前提下,让BattleService可以调用B()和C()。
可行方案一:基于接口隔离+依赖倒置的扩展实现
通过拆分抽象接口,为不同武器定义专属抽象,同时让BattleService依赖这些抽象而非具体类,既满足依赖倒置,又能安全访问子类独有方法。
代码实现
// 基础武器接口,保留通用方法 public interface Weapon { void A(); } // 剑专属接口,继承基础接口并定义独有方法 public interface SwordWeapon extends Weapon { void B(); } // 弓专属接口,继承基础接口并定义独有方法 public interface BowWeapon extends Weapon { void C(); } // Sword实现剑专属接口 public class Sword implements SwordWeapon { @Override public void A() { System.out.println("Sword A"); } @Override public void B() { System.out.println("Sword B"); } } // Bow实现弓专属接口 public class Bow implements BowWeapon { @Override public void A() { System.out.println("Bow A"); } @Override public void C() { System.out.println("Bow C"); } } // BattleService通过重载构造方法和专属方法,依赖不同抽象接口 public class BattleService { private Weapon weapon; private SwordWeapon swordWeapon; private BowWeapon bowWeapon; // 通用构造方法,适配所有武器 public BattleService(Weapon weapon) { this.weapon = weapon; } // 剑专属构造方法,依赖剑的抽象接口 public BattleService(SwordWeapon swordWeapon) { this.weapon = swordWeapon; this.swordWeapon = swordWeapon; } // 弓专属构造方法,依赖弓的抽象接口 public BattleService(BowWeapon bowWeapon) { this.weapon = bowWeapon; this.bowWeapon = bowWeapon; } // 通用方法调用 public void A() { weapon.A(); } // 剑独有方法调用,仅注入剑时可用 public void useSwordSkillB() { if (swordWeapon != null) { swordWeapon.B(); } else { throw new UnsupportedOperationException("当前武器不是剑,无法调用方法B"); } } // 弓独有方法调用,仅注入弓时可用 public void useBowSkillC() { if (bowWeapon != null) { bowWeapon.C(); } else { throw new UnsupportedOperationException("当前武器不是弓,无法调用方法C"); } } } // 客户端测试 public class Main { public static void main(String[] args) { // 使用剑 SwordWeapon sword = new Sword(); BattleService swordBattle = new BattleService(sword); swordBattle.A(); swordBattle.useSwordSkillB(); // 使用弓 BowWeapon bow = new Bow(); BattleService bowBattle = new BattleService(bow); bowBattle.A(); bowBattle.useBowSkillC(); } }
方案说明
- 接口隔离:为不同武器定义专属抽象接口,既继承通用方法,又声明独有方法,符合单一职责原则。
- 依赖倒置:
BattleService依赖的是抽象接口而非具体类,高层模块不依赖底层实现。 - 安全访问:通过专属构造方法和方法,确保只有注入对应武器抽象时才能调用独有方法,避免类型转换风险。
可行方案二:访问者模式(适合复杂武器体系)
如果后续会扩展更多武器类型,访问者模式可以更好地解耦武器与操作逻辑:
代码实现
// 定义访问者接口,声明对不同武器的操作 public interface WeaponVisitor { void visitSword(Sword sword); void visitBow(Bow bow); } // 修改基础武器接口,添加接受访问的方法 public interface Weapon { void A(); void accept(WeaponVisitor visitor); } // 修改Sword类,实现accept方法 public class Sword implements Weapon { @Override public void A() { System.out.println("Sword A"); } public void B() { System.out.println("Sword B"); } @Override public void accept(WeaponVisitor visitor) { visitor.visitSword(this); } } // 修改Bow类,实现accept方法 public class Bow implements Weapon { @Override public void A() { System.out.println("Bow A"); } public void C() { System.out.println("Bow C"); } @Override public void accept(WeaponVisitor visitor) { visitor.visitBow(this); } } // BattleService集成访问者逻辑,实现对不同武器的独有方法调用 public class BattleService implements WeaponVisitor { private Weapon weapon; public BattleService(Weapon weapon) { this.weapon = weapon; } public void A() { weapon.A(); } // 统一入口调用独有技能 public void useUniqueSkill() { weapon.accept(this); } @Override public void visitSword(Sword sword) { sword.B(); } @Override public void visitBow(Bow bow) { bow.C(); } } // 客户端测试 public class Main { public static void main(String[] args) { BattleService swordBattle = new BattleService(new Sword()); swordBattle.A(); swordBattle.useUniqueSkill(); // 调用Sword的B方法 BattleService bowBattle = new BattleService(new Bow()); bowBattle.A(); bowBattle.useUniqueSkill(); // 调用Bow的C方法 } }
方案说明
- 访问者模式将武器的独有操作从武器类中分离,
BattleService作为访问者实现对不同武器的方法调用。 - 遵循依赖倒置原则:
Weapon接口定义accept方法,BattleService依赖Weapon和WeaponVisitor抽象,不直接依赖具体武器类。 - 扩展性好:新增武器时,只需扩展
WeaponVisitor并添加对应visit方法,无需修改现有BattleService核心逻辑。
内容的提问来源于stack exchange,提问作者colin
相关产品推荐
相关产品推荐

