深入浅出设计模式区别
一、设计模式是什么?——编程界的"武功秘籍"
想象你是一名武林高手,设计模式就是你掌握的武功招式:
- 单例模式:独门绝技,天下无双
- 工厂模式:批量生产暗器的作坊
- 观察者模式:千里传音之术
但有些招式看起来很像,今天我们就来拆解这些"形似神不似"的设计模式。
二、容易混淆的"双胞胎"模式
1. 工厂三兄弟:小卖部 vs 专卖店 vs 超市
简单工厂(小卖部)
// 啥都能造的小卖部
public class WeaponStore {
public Weapon sellWeapon(String type) {
switch(type) {
case "sword": return new Sword();
case "gun": return new Gun();
default: throw new IllegalArgumentException();
}
}
}
特点:一个方法搞定所有产品,新增产品要修改代码
工厂方法(专卖店)
// 武器专卖店接口
public interface WeaponShop {
Weapon sellWeapon();
}
// 剑专卖店
public class SwordShop implements WeaponShop {
public Weapon sellWeapon() { return new Sword(); }
}
// 枪专卖店
public class GunShop implements WeaponShop {
public Weapon sellWeapon() { return new Gun(); }
}
特点:一类产品一个工厂,扩展方便但类会增多
抽象工厂(武器超市)
// 能买全套装备的超市
public interface Armory {
Weapon sellWeapon();
Armor sellArmor();
}
// 现代武器超市
public class ModernArmory implements Armory {
public Weapon sellWeapon() { return new Gun(); }
public Armor sellArmor() { return new BulletproofVest(); }
}
// 冷兵器超市
public class MedievalArmory implements Armory {
public Weapon sellWeapon() { return new Sword(); }
public Armor sellArmor() { return new PlateArmor(); }
}
特点:生产成套产品,适合产品族场景
总结:
- 要简单:小卖部(简单工厂)
- 要扩展:专卖店(工厂方法)
- 要套装:超市(抽象工厂)
2. 观察者 vs 发布订阅:班主任通知 vs 校园广播
观察者模式(班主任直接通知)
// 班主任(被观察者)
public class Teacher extends Observable {
void announce(String msg) {
setChanged();
notifyObservers(msg); // 直接通知学生
}
}
// 学生(观察者)
public class Student implements Observer {
void update(Observable o, Object msg) {
System.out.println("收到通知:" + msg);
}
}
特点:老师和学生直接联系
发布订阅模式(校园广播站)
// 广播站(中介)
public class RadioStation {
private Map<String, List<Listener>> channels = new HashMap<>();
void subscribe(String channel, Listener listener) {
channels.computeIfAbsent(channel, k -> new ArrayList<>()).add(listener);
}
void publish(String channel, String msg) {
channels.getOrDefault(channel, Collections.emptyList())
.forEach(listener -> listener.onMessage(msg));
}
}
// 学生只需要监听感兴趣频道
radio.subscribe("放学通知", msg -> System.out.println(msg));
特点:通过广播站中转,双方不知道对方存在
区别:
- 观察者:直接通信,耦合度高
- 发布订阅:通过中介,完全解耦
3. 策略 vs 状态:主动换刀 vs 自动变形
策略模式(主动切换武器)
// 游戏角色
public class Character {
private Weapon weapon; // 当前武器策略
void changeWeapon(Weapon newWeapon) {
this.weapon = newWeapon; // 主动更换
}
void attack() {
weapon.attack(); // 使用当前武器攻击
}
}
// 使用
character.changeWeapon(new Sword());
character.attack();
特点:外部主动设置策略
状态模式(自动状态转换)
// 自动售货机
public class VendingMachine {
private State state = new IdleState();
// 状态自动转换
void insertCoin() {
state.insertCoin(this);
}
void changeState(State newState) {
this.state = newState;
}
}
// 空闲状态
public class IdleState implements State {
void insertCoin(VendingMachine vm) {
System.out.println("投币成功");
vm.changeState(new HasCoinState()); // 自动切换状态
}
}
特点:状态对象控制转换逻辑
关键区别:
- 策略模式:客户端主动选择算法
- 状态模式:状态对象自动管理转换
4. 装饰者 vs 代理:套娃增强 vs 门面控制
装饰者模式(给武器附魔)
// 基础武器
public interface Weapon {
void attack();
}
// 火焰附魔
public class FireEnchantment implements Weapon {
private Weapon decoratedWeapon;
public FireEnchantment(Weapon weapon) {
this.decoratedWeapon = weapon;
}
public void attack() {
decoratedWeapon.attack();
System.out.println("附带火焰伤害!");
}
}
// 使用
Weapon sword = new Sword();
Weapon fireSword = new FireEnchantment(sword);
fireSword.attack();
特点:递归嵌套,层层增强
代理模式(武器店老板)
// 武器店代理
public class WeaponShopProxy implements Weapon {
private RealWeaponShop shop;
private boolean access;
public WeaponShopProxy(boolean vip) {
this.access = vip;
}
public void attack() {
if (access) {
if (shop == null) {
shop = new RealWeaponShop(); // 延迟加载
}
shop.attack();
} else {
System.out.println("非VIP不能使用神器");
}
}
}
特点:控制访问,可能不直接转发
核心差异:
- 装饰者:重在增强功能
- 代理:重在控制访问
三、快速选择指南
遇到问题时的选择思路:
-
创建对象:
- 简单创建 → 简单工厂
- 需要扩展 → 工厂方法
- 创建套装 → 抽象工厂
- 复杂构造 → 建造者
-
行为管理:
- 主动切换算法 → 策略模式
- 自动状态流转 → 状态模式
- 固定流程模板 → 模板方法
-
对象增强:
- 功能叠加 → 装饰者
- 访问控制 → 代理
- 接口转换 → 适配器
四、记忆口诀
-
工厂三兄弟:
- 简单工厂:一个工厂啥都造
- 工厂方法:一个产品一工厂
- 抽象工厂:一套产品一工厂
-
观察 vs 发布订阅:
- 观察者:直接打电话
- 发布订阅:群里发公告
-
策略 vs 状态:
- 策略:我选武器
- 状态:武器自动变形
-
装饰者 vs 代理:
- 装饰者:套娃增强
- 代理:门卫把关
五、总结
设计模式的区别就像不同的工具:
- 螺丝刀和锤子:虽然都是工具,但用途不同
- 不同型号螺丝刀:适合不同规格的螺丝
关键区分点:
- 意图:这个模式要解决什么问题?
- 关系:类之间如何交互?
- 变化点:什么是可变的?什么是稳定的?
记住:没有最好的模式,只有最适合的模式。就像不能拿螺丝刀当锤子用,根据实际场景选择合适的设计模式才是正道!