🎮 第一幕:西游世界的代码启示录
1. 基础概念重铸
// 抽象类:妖怪的本质(是什么)
abstract class Demon {
// 不需要重写的方法
void appear() {
System.out.println("妖气冲天!");
}
// 必须实现的抽象方法
abstract void uniqueSkill();
}
// 接口:妖怪的能力(能做什么)
interface FlameMagic {
default void fireAttack() { // 可不重写
System.out.println("释放三昧真火");
}
}
// 大Boss现身!
class RedBoy extends Demon implements FlameMagic {
@Override
void uniqueSkill() {
System.out.println("召唤火尖枪阵列");
}
// 重写默认方法
@Override
public void fireAttack() {
System.out.println("🔥 八荒焚天诀!");
}
}
2. 黄金三问解析
-
Q1:为什么模板模式可以不用final?
- 技术真相:不用final时子类仍可重写父类方法,但会破坏模板结构(比如黑熊精突然改变战斗流程)
- 最佳实践:应该用final保护模板流程:
abstract class BattlePhase { // 锁定战斗流程 public final void execute() { prepare(); attack(); escape(); } protected abstract void prepare(); protected abstract void attack(); protected void escape() { // 钩子方法 System.out.println("土遁逃脱"); } }
-
Q2:"是什么" vs "能做什么"如何区分?
- 抽象类案例:
SpiritMacaque
(灵明石猴)定义猴类本质属性 - 接口案例:
七十二变
、法天象地
作为可装配能力 - 组合威力:
class SunWukong extends SpiritMacaque implements 七十二变, 法天象地, 金刚不坏 { // 既是石猴(本质),又有各种神通(能力) }
- 抽象类案例:
⚔️ 第二幕:黑神话战斗系统架构实战
1. 模板模式深度应用
abstract class BossBattle {
// 最终决战流程(不可修改)
public final void battleProcess() {
phase1();
phase2();
enragePhase();
}
// 第一阶段通用逻辑
private void phase1() {
System.out.println("召唤小妖助阵");
meleeAttack();
}
// 抽象方法:各Boss不同表现
protected abstract void meleeAttack();
protected abstract void phase2();
// 狂暴阶段(可选重写)
protected void enragePhase() {
System.out.println("进入狂暴状态!");
}
}
// 黄风怪实现
class YellowWindDemonBattle extends BossBattle {
protected void meleeAttack() {
System.out.println("三股叉连续突刺");
}
protected void phase2() {
System.out.println("召唤沙尘暴领域");
}
@Override
protected void enragePhase() {
System.out.println("黄风大葬!天地变色");
}
}
2. 接口的灵活装配
// 法宝能力接口
interface MagicTreasure {
default void activate() {
System.out.println("法宝基础效果触发");
}
}
// 具体法宝实现
class GoldenHoops implements MagicTreasure {
@Override
public void activate() {
System.out.println("金箍棒变大横扫千军!");
}
}
class WindFireWheel implements MagicTreasure {
// 不重写则使用默认效果
}
// 战斗中使用
class BattleSystem {
void useTreasure(MagicTreasure treasure) {
treasure.activate(); // 多态生效
}
}
// 实战演示:
BattleSystem system = new BattleSystem();
system.useTreasure(new GoldenHoops()); // 金箍棒特效
system.useTreasure(new WindFireWheel());// 默认法宝效果
🔮 第三幕:进阶设计哲学
1. 模板模式的三大铁律
- 流程固化:把确定的流程钉死在模板方法里(就像黑神话的BOSS战阶段)
- 弹性扩展:通过钩子方法(Hook Method)允许选择性重写
- 好莱坞原则:"不要调用我们,我们会调用你"——子类只需填空,不用管流程
2. 接口的现代进化
interface CombatStyle {
// 默认方法实现连招模板
default void comboAttack() {
lightAttack();
heavyAttack();
specialMove();
}
private void lightAttack() {
System.out.println("轻攻击");
}
abstract void heavyAttack();
abstract void specialMove();
}
// 实现示例
class SpearStyle implements CombatStyle {
public void heavyAttack() {
System.out.println("长枪突刺");
}
public void specialMove() {
System.out.println("游龙掷月枪");
}
}
// 使用时:
CombatStyle style = new SpearStyle();
style.comboAttack(); // 轻攻→突刺→必杀技
3. 终极对比表
特性 | 抽象类 | 接口 |
---|---|---|
设计定位 | 本质继承(是什么) | 能力装配(能做什么) |
模板模式适用度 | ★★★★★ | ★★☆ (通过默认方法有限支持) |
多态方向 | 自上而下 | 自下而上 |
代码复用 | 共享父类代码 | 通过默认方法共享 |
黑神话应用案例 | BOSS战流程模板 | 法宝/神通系统 |
口语化解释一下接口和抽象类多态的区别,抽象类是用于是什么的场景,接口是用于能做什么的场景。感觉更好区分的是,抽象类中间可用模板模式,进行方法的链式制定。 (个人观点,请多指正)
补充:
🟢 抽象类的正确打开方式(模板方法示例):
abstract class Beverage {
// 模板方法:控制制作流程
public final void prepare() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 公共实现
private void boilWater() {
System.out.println("煮沸100℃水");
}
// 抽象方法
protected abstract void brew();
protected abstract void addCondiments();
}
class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("冲泡咖啡粉");
}
@Override
protected void addCondiments() {
System.out.println("加奶加糖");
}
}
🔵 接口的正确打开方式(策略模式示例):
interface Flyable {
void fly(); // 能力契约
}
interface Quackable {
void quack();
}
class RocketDuck extends Duck implements Flyable, Quackable {
public void fly() {
System.out.println("喷气式飞行");
}
public void quack() {
System.out.println("电子音鸣叫");
}
}
💡 关键区分点表格:
特性 | 抽象类 | 接口 |
---|---|---|
设计目的 | 代码复用 + 多态扩展 | 行为契约 + 能力组合 |
模板方法适用性 | ✅ 天然支持 | ❌ 无法定义方法实现 |
多态维度 | 纵向继承(是什么) | 横向扩展(能做什么) |
成员类型 | 可含字段/具体方法 | 仅抽象方法/默认方法 |
设计模式 | 模板方法、工厂方法 | 策略、装饰器、适配器 |
🔍 为什么模板方法必须用抽象类:
- 需要固化流程(final方法控制步骤顺序)
- 需要共享公共代码(如boilWater方法)
- 需要定义抽象方法的调用结构
🚫 接口无法实现模板方法的情况:
interface Template { // 反模式示例
default void process() {
step1(); // 错误!接口默认方法不能调用未实现的抽象方法
step2();
}
void step1();
void step2();
}
✅ 但Java8+的接口可以通过默认方法实现简单流程(有限制):
interface Loggable {
default void logProcess() {
String msg = formatMessage(); // 调用抽象方法
saveToFile(msg);
}
String formatMessage(); // 仍需实现
private void saveToFile(String msg) {
// 公共日志保存逻辑
}
}