无需instanceof或强制转换,实现父类调用子类方法的类重构方案
无需强制转换调用子类独有方法的重构方案
针对你提出的Java类结构重构需求,以下是几种可行的实现方案,均避免使用instanceof或强制类型转换:
方案一:基于能力接口的适配模式
通过定义独立的能力接口,让子类按需实现,再在抽象父类中提供统一的能力获取方法,既保持父类的简洁性,又能灵活扩展子类能力。
代码实现
- 定义银行账户专属能力接口
public interface BankAccountCapability { String getAccountNumber(); void setAccountNumber(String accountNumber); }
- 修改抽象
Account类,添加能力获取方法
public abstract class Account { private double balance; private String password; // 原有getter/setter方法 public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } // 泛型方法,安全获取指定类型的能力 @SuppressWarnings("unchecked") public <T> Optional<T> getCapability(Class<T> capabilityType) { if (capabilityType.isInstance(this)) { return Optional.of((T) this); } return Optional.empty(); } }
- 让
BankAccount实现能力接口
public class BankAccount extends Account implements BankAccountCapability { private String accountNumber; @Override public String getAccountNumber() { return accountNumber; } @Override public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; } }
WalletAccount保持原有结构即可
public class WalletAccount extends Account { // 钱包账户专属逻辑 }
调用示例
Account account = new BankAccount(); account.getCapability(BankAccountCapability.class) .ifPresent(cap -> cap.setAccountNumber("622848xxxxxx1234")); account.getCapability(BankAccountCapability.class) .ifPresent(cap -> System.out.println("账户号:" + cap.getAccountNumber()));
优缺点
- 优点:父类无需新增子类专属方法,符合单一职责原则;新增子类能力只需添加新接口,扩展性强。
- 缺点:调用时需通过
getCapability方法获取能力,写法比直接调用多一层包装。
方案二:抽象类新增默认方法
在抽象Account类中定义子类独有的方法默认实现,子类按需重写该方法,直接通过父类引用调用,完全匹配需求中的写法。
代码实现
- 修改抽象
Account类,添加默认方法
public abstract class Account { private double balance; private String password; // 原有getter/setter方法 public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } // 默认返回空Optional,避免空指针 public Optional<String> getAccountNumber() { return Optional.empty(); } // 默认抛出不支持操作异常,提示非法调用 public void setAccountNumber(String accountNumber) { throw new UnsupportedOperationException("当前账户类型不支持设置账户号"); } }
BankAccount重写方法
public class BankAccount extends Account { private String accountNumber; @Override public Optional<String> getAccountNumber() { return Optional.ofNullable(accountNumber); } @Override public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; } }
调用示例
Account account = new BankAccount(); account.setAccountNumber("622848xxxxxx1234"); account.getAccountNumber().ifPresent(num -> System.out.println("账户号:" + num));
优缺点
- 优点:调用方式完全符合需求中的
account.getAccountNumber()写法,直观简洁。 - 缺点:抽象类会逐渐积累子类专属方法,违反单一职责原则;钱包账户调用该方法会抛出异常,需做好异常处理。
方案三:访问者模式
通过访问者模式分离数据结构和操作,针对不同类型的账户实现不同的访问逻辑,适合需要对不同账户类型执行多组操作的场景。
代码实现
- 定义访问者接口
public interface AccountVisitor { void visitBankAccount(BankAccount account); void visitWalletAccount(WalletAccount account); }
- 修改抽象
Account类,添加接受访问的方法
public abstract class Account { private double balance; private String password; // 原有getter/setter方法 public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public abstract void accept(AccountVisitor visitor); }
- 子类实现
accept方法
public class BankAccount extends Account { private String accountNumber; public String getAccountNumber() { return accountNumber; } public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; } @Override public void accept(AccountVisitor visitor) { visitor.visitBankAccount(this); } } public class WalletAccount extends Account { @Override public void accept(AccountVisitor visitor) { visitor.visitWalletAccount(this); } }
- 实现具体访问者(比如获取账户号的访问者)
public class AccountNumberVisitor implements AccountVisitor { private String accountNumber; @Override public void visitBankAccount(BankAccount account) { this.accountNumber = account.getAccountNumber(); } @Override public void visitWalletAccount(WalletAccount account) { this.accountNumber = null; // 钱包账户无账户号 } public String getAccountNumber() { return accountNumber; } }
调用示例
Account account = new BankAccount(); ((BankAccount) account).setAccountNumber("622848xxxxxx1234"); AccountNumberVisitor visitor = new AccountNumberVisitor(); account.accept(visitor); System.out.println("账户号:" + visitor.getAccountNumber());
优缺点
- 优点:操作与数据结构分离,新增操作只需添加新的访问者类,符合开闭原则。
- 缺点:结构相对复杂,若新增账户类型需修改访问者接口,违反开闭原则;调用需借助访问者实例,写法不够直接。
内容的提问来源于stack exchange,提问作者Mohamed Amir
相关产品推荐
相关产品推荐

