安卓开发设计模式(三)——行为型设计模式

行为型设计模式专注于对象间的交互逻辑和职责分配,通过定义对象间的通信方式、行为分配规则,实现行为的复用、解耦与灵活扩展。核心是解决“对象如何协作完成任务”的问题,不改变对象的内部结构,而是优化对象间的协作关系,让系统更具灵活性和可维护性。

常见模式

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-elseswitch判断逻辑,提高代码可读性和可维护性
  • 算法细节需要隐藏,仅通过统一接口对外提供服务

以支付场景为例,封装不同支付方式作为策略:

// 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);
        }
        // 输出:
        // 菜单菜品:
        // - 宫保鸡丁
        // - 鱼香肉丝
        // - 麻婆豆腐
    }
}

简单来说就是:迭代器封装遍历细节、聚合对象提供迭代器、用户依赖迭代器接口,实现了将聚合对象的遍历逻辑与集合本身分离

优点:统一遍历接口,客户端代码更简洁,聚合对象内部结构变化时无需修改客户端遍历逻辑;缺点:对于简单聚合对象,使用迭代器会增加不必要的代码复杂度,还需额外处理并发问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值