面试题答案
一键面试抽象类作为策略定义方式的场景
- 当策略需要有部分通用实现时:如果多个具体策略有一些共同的属性或方法实现,使用抽象类可以将这些通用部分提取出来,避免在具体策略类中重复编写。例如,在一个图形绘制的策略模式中,不同图形(圆形、矩形等)的绘制可能都需要获取画笔相关的操作,这些获取画笔的操作可以放在抽象类中实现。
- 当策略需要继承其他类时:Java 不支持多重继承,若策略类需要继承自某个特定类,同时又作为策略定义,此时抽象类是合适的选择。
接口作为策略定义方式的场景
- 当策略只关注行为定义,没有通用实现时:如果每个具体策略的实现完全不同,仅仅需要定义一组行为规范,接口是更好的选择。例如,在一个支付策略模式中,微信支付、支付宝支付、银行卡支付等具体实现差异很大,只需要定义统一的支付接口方法,如
pay(double amount)
。 - 希望策略具有更高的灵活性和扩展性:接口允许多个类实现,一个类还可以实现多个接口,这使得系统在扩展新策略时更加灵活。
代码结构差异示例
- 以抽象类作为策略定义
// 抽象策略类
abstract class DrawStrategy {
// 通用方法
protected void getPen() {
System.out.println("获取画笔");
}
// 抽象方法,具体策略实现
abstract void draw();
}
// 具体策略类 - 绘制圆形
class CircleDrawStrategy extends DrawStrategy {
@Override
void draw() {
getPen();
System.out.println("绘制圆形");
}
}
// 具体策略类 - 绘制矩形
class RectangleDrawStrategy extends DrawStrategy {
@Override
void draw() {
getPen();
System.out.println("绘制矩形");
}
}
// 上下文类
class DrawingContext {
private DrawStrategy drawStrategy;
public DrawingContext(DrawStrategy drawStrategy) {
this.drawStrategy = drawStrategy;
}
public void executeDraw() {
drawStrategy.draw();
}
}
- 以接口作为策略定义
// 策略接口
interface PayStrategy {
void pay(double amount);
}
// 具体策略类 - 微信支付
class WeChatPayStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
}
}
// 具体策略类 - 支付宝支付
class AlipayPayStrategy implements PayStrategy {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
}
}
// 上下文类
class PaymentContext {
private PayStrategy payStrategy;
public PaymentContext(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
public void executePay() {
payStrategy.pay(this.amount);
}
}
从上述代码可以看出,使用抽象类时,具体策略类继承抽象策略类,可以复用抽象类中的通用方法;而使用接口时,具体策略类实现接口,接口中只有方法声明,没有实现,具体策略的实现完全由实现类自行完成。