行为型设计模式专注于对象间的交互逻辑和职责分配,通过定义对象间的通信方式、行为分配规则,实现行为的复用、解耦与灵活扩展。核心是解决“对象如何协作完成任务”的问题,不改变对象的内部结构,而是优化对象间的协作关系,让系统更具灵活性和可维护性。
常见模式
1.观察者模式
观察者模式定义对象间的一对多依赖关系,当一个对象(被观察者)的状态发生变化时,所有依赖它的对象(观察者)都会收到通知并自动更新。就像微信公众号与订阅用户:公众号是被观察者,订阅用户是观察者,公众号发布新内容(状态变化)时,所有订阅用户都会收到推送通知。
核心解决问题:
- 一个对象状态变化需要同步通知多个关联对象,且避免对象间直接耦合
- 需支持动态添加 / 移除观察者,不影响被观察者的核心业务逻辑
- 观察者与被观察者无需知道对方的具体实现,仅依赖抽象接口通信
简单示例
// 1. 观察者接口(定义接收通知的行为)
public interface Observer {
void onUpdate(String message); // 接收被观察者的通知
}
// 2. 被观察者接口(定义注册、移除观察者及通知方法)
public interface Observable {
void registerObserver(Observer observer); // 注册观察者
void removeObserver(Observer observer); // 移除观察者
void notifyObservers(String message); // 通知所有观察者
}
// 3. 具体被观察者(微信公众号)
public class WechatOfficialAccount implements Observable {
private List<Observer> observers = new ArrayList<>();
private String accountName;
public WechatOfficialAccount(String accountName) {
this.accountName = accountName;
}
// 发布文章(状态变化)
public void publishArticle(String articleTitle) {
String message = accountName + "发布了新文章:《" + articleTitle + "》";
notifyObservers(message); // 通知所有观察者
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
// 遍历所有观察者并发送通知
for (Observer observer : observers) {
observer.onUpdate(message);
}
}
}
// 4. 具体观察者(订阅用户)
public class User implements Observer {
private String userName;
public User(String userName) {
this.userName = userName;
}
@Override
public void onUpdate(String message) {
System.out.println(userName + "收到通知:" + message);
}
}
// 5. 使用示例
public class ObserverDemo {
public static void main(String[] args) {
// 创建被观察者(公众号)
WechatOfficialAccount account = new WechatOfficialAccount("安卓开发进阶");
// 创建观察者(用户)
Observer user1 = new User("张三");
Observer user2 = new User("李四");
// 订阅公众号
account.registerObserver(user1);
account.registerObserver(user2);
// 公众号发布文章
account.publishArticle("行为型设计模式实战");
// 输出:
// 张三收到通知:安卓开发进阶发布了新文章:《行为型设计模式实战》
// 李四收到通知:安卓开发进阶发布了新文章:《行为型设计模式实战》
// 李四取消订阅
account.removeObserver(user2);
account.publishArticle("Jetpack组件全家桶");
// 输出:
// 张三收到通知:安卓开发进阶发布了新文章:《Jetpack组件全家桶》
}
}
安卓中的经典体现
安卓开发中经典的观察者模式就是LiveData,它是生命周期感知的被观察者,能自动关联Activity/Fragment的生命周期,避免内存泄漏
// LiveData使用示例(生命周期感知的观察者模式)
public class MainActivity extends AppCompatActivity {
// 创建被观察者(LiveData)
private MutableLiveData<String> messageLiveData = new MutableLiveData<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 注册观察者(关联Activity生命周期)
messageLiveData.observe(this, new Observer<String>() {
@Override
public void onChanged(String message) {
// 收到通知后更新UI
TextView tvMessage = findViewById(R.id.tv_message);
tvMessage.setText(message);
}
});
// 模拟状态变化(发送通知)
findViewById(R.id.btn_send).setOnClickListener(v -> {
messageLiveData.setValue("LiveData发送的通知:设计模式学习完成!");
});
}
}
被观察者仅依赖Observer抽象接口,不关心具体观察者类型;观察者也无需知道被观察者的内部实现,只需响应通知
优点:支持动态增减观察者,灵活性高,LiveData额外解决了生命周期管理问题,避免内存泄漏;缺点:如果观察者过多,通知遍历会影响性能,观察者与被观察者间可能存在循环依赖风险
2.策略模式
策略模式定义一系列算法,将每个算法封装成独立的策略类,并使它们可以相互替换。让算法的变化独立于使用算法的客户端,客户端只需根据场景选择合适的策略,无需关心算法的具体实现。就像出门旅行的交通方式:飞机、高铁、汽车是不同的“策略”,用户可根据时间、预算动态切换,而不改变“到达目的地”的核心目标
核心解决问题:
- 多个类似算法 / 行为并存,需根据业务场景动态切换(如支付方式、排序算法)
- 避免使用大量if-else或switch判断逻辑,提高代码可读性和可维护性
- 算法细节需要隐藏,仅通过统一接口对外提供服务
以支付场景为例,封装不同支付方式作为策略:
// 1. 策略接口(定义统一的支付行为)
public interface PaymentStrategy {
boolean pay(double amount); // 支付方法,返回支付结果
String getPaymentName(); // 获取支付方式名称
}
// 2. 具体策略1:支付宝支付
public class AlipayStrategy implements PaymentStrategy {
private String userId;
public AlipayStrategy(String userId) {
this.userId = userId;
}
@Override
public boolean pay(double amount) {
System.out.println("支付宝用户[" + userId + "]发起支付,金额:" + amount + "元");
// 模拟支付成功逻辑
return true;
}
@Override
public String getPaymentName() {
return "支付宝支付";
}
}
// 3. 具体策略2:微信支付
public class WechatPayStrategy implements PaymentStrategy {
private String wechatId;
public WechatPayStrategy(String wechatId) {
this.wechatId = wechatId;
}
@Override
public boolean pay(double amount) {
System.out.println("微信用户[" + wechatId + "]发起支付,金额:" + amount + "元");
// 模拟支付成功逻辑
return true;
}
@Override
public String getPaymentName() {
return "微信支付";
}
}
// 4. 策略上下文(统一调度策略,对外提供简单接口)
public class PaymentManager {
private PaymentStrategy strategy;
// 设置当前支付策略
public void setPaymentStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
// 执行支付
public boolean executePayment(double amount) {
if (strategy == null) {
throw new IllegalStateException("请选择支付方式");
}
System.out.println("当前支付方式:" + strategy.getPaymentName());
return strategy.pay(amount);
}
}
// 5. 使用示例
public class StrategyDemo {
public static void main(String[] args) {
PaymentManager paymentManager = new PaymentManager();
double orderAmount = 99.0;
// 选择支付宝支付
paymentManager.setPaymentStrategy(new AlipayStrategy("zhangsan123"));
boolean alipayResult = paymentManager.executePayment(orderAmount);
System.out.println("支付宝支付结果:" + (alipayResult ? "成功" : "失败"));
// 切换为微信支付
paymentManager.setPaymentStrategy(new WechatPayStrategy("wx_456"));
boolean wechatResult = paymentManager.executePayment(orderAmount);
System.out.println("微信支付结果:" + (wechatResult ? "成功" : "失败"));
}
}
安卓中的经典体现
安卓中RecyclerView.LayoutManager是策略模式的典型应用:LinearLayoutManager、GridLayoutManage都是不同的布局策略,可动态切换而不修改RecyclerView的核心逻辑
// RecyclerView切换布局策略示例
public class LayoutStrategyDemo extends AppCompatActivity {
private RecyclerView recyclerView;
private UserAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout_strategy);
recyclerView = findViewById(R.id.recycler_view);
adapter = new UserAdapter(getUserList());
// 初始使用线性布局策略
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
// 点击按钮切换为网格布局策略(2列)
findViewById(R.id.btn_grid).setOnClickListener(v -> {
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
});
// 点击按钮切换为瀑布流布局策略(2列)
findViewById(R.id.btn_staggered).setOnClickListener(v -> {
recyclerView.setLayoutManager(
new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
);
});
}
private List<User> getUserList() {
return Arrays.asList(
new User("张三", "zhangsan@example.com"),
new User("李四", "lisi@example.com"),
new User("王五", "wangwu@example.com")
);
}
}
优点:新增策略只需实现接口,符合开闭原则,消除多重条件判断,代码结构清晰;缺点:策略类数量会随算法增多而增加,客户端需要了解不同策略的差异
3.命令模式
命令模式将一个请求封装成一个对象(命令),使请求的发送者(客户端)与接收者(执行对象)解耦,发送者只需调用命令对象的执行方法,无需知道接收者是谁、如何执行请求;就像电视遥控器:遥控器(发送者)按下“开机”(命令对象),电视(接收者)执行开机操作,遥控器无需知道电视的开机原理,只需触发命令
核心解决问题:
- 解耦请求发送者与接收者,发送者无需知道接收者的具体实现
- 支持请求的异步执行、排队处理、日志处理、撤销 / 重做
- 需将多个分散的请求封装成统一对象,便于管理和扩展
简单示例
// 1. 命令接口(定义命令的执行与撤销行为)
public interface Command {
void execute(); // 执行命令
void undo(); // 撤销命令(可选)
}
// 2. 接收者(家电:电视)
public class TV {
private String name;
private boolean isOn;
public TV(String name) {
this.name = name;
this.isOn = false;
}
// 接收者的核心功能:开机
public void turnOn() {
if (!isOn) {
isOn = true;
System.out.println(name + "已开机");
} else {
System.out.println(name + "已处于开机状态");
}
}
// 接收者的核心功能:关机
public void turnOff() {
if (isOn) {
isOn = false;
System.out.println(name + "已关机");
} else {
System.out.println(name + "已处于关机状态");
}
}
public boolean isOn() {
return isOn;
}
}
// 3. 具体命令1:开机命令
public class TurnOnCommand implements Command {
private TV tv; // 持有接收者引用
public TurnOnCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turnOn(); // 调用接收者的开机方法
}
@Override
public void undo() {
tv.turnOff(); // 撤销:执行相反操作(关机)
}
}
// 4. 具体命令2:关机命令
public class TurnOffCommand implements Command {
private TV tv;
public TurnOffCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turnOff(); // 调用接收者的关机方法
}
@Override
public void undo() {
tv.turnOn(); // 撤销:执行相反操作(开机)
}
}
// 5. 发送者(遥控器)
public class RemoteControl {
private Command command; // 持有当前命令对象
private Stack<Command> commandHistory = new Stack<>(); // 命令历史(用于撤销)
// 设置当前要执行的命令
public void setCommand(Command command) {
this.command = command;
}
// 触发命令执行
public void pressButton() {
if (command != null) {
command.execute();
commandHistory.push(command); // 记录命令到历史栈
} else {
System.out.println("未设置命令");
}
}
// 撤销上一次命令
public void pressUndoButton() {
if (!commandHistory.isEmpty()) {
Command lastCommand = commandHistory.pop();
lastCommand.undo();
System.out.println("撤销上一次操作");
} else {
System.out.println("无操作可撤销");
}
}
}
// 6. 使用示例
public class CommandDemo {
public static void main(String[] args) {
// 创建接收者(电视)
TV livingRoomTV = new TV("客厅电视");
// 创建命令对象
Command turnOnCommand = new TurnOnCommand(livingRoomTV);
Command turnOffCommand = new TurnOffCommand(livingRoomTV);
// 创建发送者(遥控器)
RemoteControl remote = new RemoteControl();
// 执行开机命令
remote.setCommand(turnOnCommand);
remote.pressButton(); // 输出:客厅电视已开机
// 执行关机命令
remote.setCommand(turnOffCommand);
remote.pressButton(); // 输出:客厅电视已关机
// 撤销关机命令
remote.pressUndoButton(); // 输出:客厅电视已开机 + 撤销上一次操作
}
}
安卓中Handler机制是命令模式的核心应用:Message/Runnable是命令对象,Handler是发送者,Looper是命令队列管理者,主线程(或子线程)是接收者,Handler.sendEmptyMessage()本质是发送一个命令对象,由Looper调度执行
// Handler命令模式示例
public class HandlerCommandDemo extends AppCompatActivity {
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
// 接收者执行命令(更新UI)
switch (msg.what) {
case 1:
TextView tv = findViewById(R.id.tv_result);
tv.setText("命令执行成功:" + msg.obj);
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_command);
// 发送者发送命令(Message是命令对象)
findViewById(R.id.btn_send_command).setOnClickListener(v -> {
Message message = Message.obtain();
message.what = 1; // 命令标识
message.obj = "Handler发送的异步任务完成"; // 命令参数
mHandler.sendMessage(message); // 发送命令
});
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null); // 销毁时清除命令队列
}
}
4.迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而无需暴露该对象的内部表示。迭代器封装了遍历逻辑,客户端通过统一的迭代器接口遍历元素,无需关心聚合对象的内部存储结构(是数组、链表还是其他)。就像餐厅服务员遍历菜单:菜单是聚合对象,服务员是迭代器,顾客只需让服务员依次上菜(遍历元素),无需知道菜单是用本子记录还是电子表格存储。
核心解决问题:
- 统一不同聚合对象的遍历方式,客户端无需适配不同的遍历逻辑
- 隐藏聚合对象的内部存储结构,提高代码的安全性和封装性
- 支持在不修改聚合对象的前提下,新增不同的遍历方式
// 1. 迭代器接口(定义遍历行为)
public interface Iterator<T> {
boolean hasNext(); // 是否还有下一个元素
T next(); // 获取下一个元素
}
// 2. 聚合接口(定义创建迭代器的方法)
public interface Aggregate<T> {
Iterator<T> createIterator(); // 创建迭代器
}
// 3. 具体聚合对象(菜单)
public class Menu implements Aggregate<String> {
private String[] dishes; // 内部存储结构(数组)
private int size;
public Menu(int capacity) {
dishes = new String[capacity];
size = 0;
}
// 添加菜品
public void addDish(String dish) {
if (size < dishes.length) {
dishes[size++] = dish;
} else {
System.out.println("菜单已满,无法添加新菜品");
}
}
// 创建迭代器
@Override
public Iterator<String> createIterator() {
return new MenuIterator();
}
// 内部迭代器类(持有聚合对象引用,实现遍历逻辑)
private class MenuIterator implements Iterator<String> {
private int index = 0; // 当前遍历索引
@Override
public boolean hasNext() {
return index < size; // 判断是否还有下一个元素
}
@Override
public String next() {
if (hasNext()) {
return dishes[index++]; // 返回当前元素并移动索引
}
throw new NoSuchElementException("没有更多菜品了");
}
}
}
// 4. 使用示例
public class IteratorDemo {
public static void main(String[] args) {
// 创建聚合对象(菜单)
Menu menu = new Menu(5);
menu.addDish("宫保鸡丁");
menu.addDish("鱼香肉丝");
menu.addDish("麻婆豆腐");
// 获取迭代器并遍历
Iterator<String> iterator = menu.createIterator();
System.out.println("菜单菜品:");
while (iterator.hasNext()) {
String dish = iterator.next();
System.out.println("- " + dish);
}
// 输出:
// 菜单菜品:
// - 宫保鸡丁
// - 鱼香肉丝
// - 麻婆豆腐
}
}
简单来说就是:迭代器封装遍历细节、聚合对象提供迭代器、用户依赖迭代器接口,实现了将聚合对象的遍历逻辑与集合本身分离
优点:统一遍历接口,客户端代码更简洁,聚合对象内部结构变化时无需修改客户端遍历逻辑;缺点:对于简单聚合对象,使用迭代器会增加不必要的代码复杂度,还需额外处理并发问题
——行为型设计模式&spm=1001.2101.3001.5002&articleId=153697642&d=1&t=3&u=77b5035aff704286b45523a62ec10be6)
203

被折叠的 条评论
为什么被折叠?



