C++如何处理对象的状态变化?

概念

处理对象的状态变化是软件开发中一个重要的课题,尤其是在设计过程中,如何有效管理对象的状态变化对于软件的可维护性、可扩展性和整体设计都至关重要。

状态模式

状态模式通过将状态封装为对象,允许对象在内部状态改变时改变其行为。状态模式使得状态的切换变得灵活,减少了条件语句的使用。

#include <iostream>  
#include <memory>  // 前向声明  
class Context;  // 抽象状态类  
class State {  
public:  virtual void handle(Context& context) = 0;  virtual ~State() = default;  
};  // 上下文类  
class Context {  
private:  std::unique_ptr<State> state;  public:  Context(std::unique_ptr<State> initialState) : state(std::move(initialState)) {}  void setState(std::unique_ptr<State> newState) {  state = std::move(newState);  }  void request() {  state->handle(*this); // 使用当前状态进行处理  }  
};  // 具体状态类 A  
class ConcreteStateA : public State {  
public:  void handle(Context& context) override {  std::cout << "Handling state A. Transitioning to state B." << std::endl;  context.setState(std::make_unique<ConcreteStateB>()); // 转换状态  }  
};  // 具体状态类 B  
class ConcreteStateB : public State {  
public:  void handle(Context& context) override {  std::cout << "Handling state B. Transitioning to state A." << std::endl;  context.setState(std::make_unique<ConcreteStateA>()); // 转换状态  }  
};  int main() {  Context context(std::make_unique<ConcreteStateA>());  context.request(); // 当前是状态 A  context.request(); // 当前是状态 B  context.request(); // 当前是状态 A  context.request(); // 当前是状态 B  return 0;  
}

代码解析

  • 状态基类:定义了处理方法的接口,子类需要实现具体行为。
  • 具体状态类:分别实现不同状态的行为,并在处理过程中改变上下文的状态。
  • 上下文类:持有一个状态对象,通过调用当前状态的 handle 方法来响应请求,并允许状态的转换。

观察者模式

观察者模式用于建立一种一对多的依赖关系,当被观察者的状态改变时,所有依赖于它的观察者都会收到通知。适用于需要通知多个对象状态变化的场景。

#include <iostream>  
#include <vector>  
#include <memory>  // 抽象观察者类  
class Observer {  
public:  virtual void update() = 0;  virtual ~Observer() = default;  
};  // 抽象被观察者类  
class Subject {  
public:  virtual void attach(std::shared_ptr<Observer> observer) = 0;  virtual void detach(std::shared_ptr<Observer> observer) = 0;  virtual void notify() = 0;  virtual ~Subject() = default;  
};  // 具体被观察者  
class ConcreteSubject : public Subject {  
private:  std::vector<std::shared_ptr<Observer>> observers;  int state;  public:  void setState(int newState) {  state = newState;  notify();  }  int getState() const {  return state;  }  void attach(std::shared_ptr<Observer> observer) override {  observers.push_back(observer);  }  void detach(std::shared_ptr<Observer> observer) override {  // 在这里可以实现 detach 逻辑  }  void notify() override {  for (const auto& observer : observers) {  observer->update(); // 通知所有观察者  }  }  
};  // 具体观察者  
class ConcreteObserver : public Observer {  
private:  ConcreteSubject& subject;  public:  ConcreteObserver(ConcreteSubject& subject) : subject(subject) {}  void update() override {  std::cout << "Observer updated: New state = " << subject.getState() << std::endl;  }  
};  int main() {  ConcreteSubject subject;  auto observer1 = std::make_shared<ConcreteObserver>(subject);  subject.attach(observer1); // 注册观察者  subject.setState(1); // 改变状态,通知观察者  subject.setState(2); // 再改变状态,通知观察者  return 0;  
}

代码解析

  • 观察者接口:定义了一个更新方法,所有具体观察者都需实现该方法。
  • 被观察者接口:定义附加、解除和通知观察者的方法。
  • 具体被观察者:持有观察者的列表,维护自己的状态,并在状态变化时通知观察者。
  • 具体观察者:在状态变化时采取相应的行动。

状态机模式

状态机模式通常用于表示有限状态机的行为,适用于状态变化明确且数量有限的场景。状态机可以维护状态转移的规则和条件。

#include <iostream>  
#include <map>  
#include <functional>  // 状态机类  
class StateMachine {  
public:  using State = std::string;  using Transition = std::function<void()>;  private:  State currentState;  std::map<State, std::map<State, Transition>> transitions;  public:  void addTransition(State from, State to, Transition transition) {  transitions[from][to] = transition; // 记录状态转移  }  void setState(State state) {  currentState = state; // 设置当前状态  }  void transition(State to) {  if (transitions[currentState].count(to)) {  transitions[currentState][to](); // 执行转移逻辑  currentState = to; // 更新当前状态  } else {  std::cout << "Invalid transition from " << currentState << " to " << to << std::endl;  }  }  State getCurrentState() const {  return currentState; // 获取当前状态  }  
};  int main() {  StateMachine sm;  // 添加状态转移  sm.addTransition("Idle", "Working", []() {  std::cout << "Transitioning from Idle to Working." << std::endl;  });  sm.addTransition("Working", "Idle", []() {  std::cout << "Transitioning from Working to Idle." << std::endl;  });  sm.setState("Idle");  sm.transition("Working"); // 有效转移  sm.transition("Idle");    // 有效转移  sm.transition("Working");  // 有效转移  sm.transition("Idle");     // 有效转移  return 0;  
}

代码解析

  • 状态机类:管理当前状态和状态转移逻辑。
  • 状态转移:通过方法 transition 来执行状态之间的切换,检查是否允许转移,并执行转移后的逻辑。

使用监听器模式

在某些情况下,可以通过事件的方式来处理状态变化,使用事件监听器来观察和处理状态变化。

#include <iostream>  
#include <vector>  
#include <string>  // 监听器接口  
class Listener {  
public:  virtual void onStateChanged(const std::string& newState) = 0;  virtual ~Listener() = default;  
};  // 主类,它的状态会变化  
class StateTracker {  
private:  std::string state;  std::vector<Listener*> listeners;  public:  void addListener(Listener* listener) {  listeners.push_back(listener);  }  void changeState(const std::string& newState) {  state = newState;  notifyListeners();  }  void notifyListeners() {  for (auto listener : listeners) {  listener->onStateChanged(state); // 通知所有监听者  }  }  
};  // 具体监听者  
class ConcreteListener : public Listener {  
public:  void onStateChanged(const std::string& newState) override {  std::cout << "State changed to: " << newState << std::endl;  }  
};  int main() {  StateTracker tracker;  ConcreteListener listener;  tracker.addListener(&listener); // 添加监听者  tracker.changeState("Active");   // 改变状态,触发通知  tracker.changeState("Inactive"); // 再改变状态,触发通知  return 0;  
}

代码解析

  • 监听器接口:定义了状态变化的响应方法。
  • 主类:持有状态并维护监听者列表,状态变化时通知所有监听者。
  • 具体监听者:实现状态变化时的处理逻辑。

总结

处理对象的状态变化通常可以通过几种设计模式和技术来实现,选择适当的方法取决于项目需求和复杂性。这些方法包括:

  • 状态模式:将不同状态封装为对象,负责相应的行为。
  • 观察者模式:允许多个观察者监视状态的变化,并在状态变化时得到通知。
  • 状态机模式:清晰地管理状态和状态之间的转移逻辑。
  • 监听器模式:以事件驱动的方式处理状态变化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63592.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在Spring中application 的配置属性(详细)

application 的配置属性。 这些属性是否生效取决于对应的组件是否声明为 Spring 应用程序上下文里的 Bean &#xff08;基本是自动配置 的&#xff09;&#xff0c;为一个不生效的组件设置属性是没有用的。 multipart multipart.enabled 开启上传支持&#xff08;默认&a…

C语言编程1.27汉诺塔

题目描述 给定一个由n个圆盘组成的塔&#xff0c;这些圆盘按照大小递减的方式套在第一根桩柱上。现要将整个塔移动到另一根桩柱上&#xff0c;每次只能移动一个圆盘&#xff0c;且较大的圆盘在移动过程中不能放置在较小的圆盘上面。 输入格式 输入由四行&#xff1a; 第一行…

初学stm32 --- 时钟配置

目录 stm32时钟系统 时钟源 &#xff08;1&#xff09; 2 个外部时钟源&#xff1a; &#xff08;2&#xff09;2 个内部时钟源&#xff1a; 锁相环 PLL PLLXTPRE&#xff1a; HSE 分频器作为 PLL 输入 (HSE divider for PLL entry) PLLSRC&#xff1a; PLL 输入时钟源 (PL…

【Java基础面试题025】什么是Java的Integer缓存池?

回答重点 Java的Integer缓存池&#xff08;Integer Cache&#xff09;是为了提升性能和节省内存。根据实践发现大部分的数据操作都集中在值比较小的范围&#xff0c;因此缓存这些对象可以减少内存分配和垃圾回收的负担&#xff0c;提升性能 在 -128到127范围内的Integer对象会…

Nginx IP优化限制策略

Nginx 如何限制每个 IP 地址的连接数&#xff0c;优化资源分配&#xff1f; Nginx 限制每个 IP 地址的连接数 Nginx 提供了多种机制来限制单个 IP 地址所能建立的同时连接数&#xff0c;这对于防止资源耗尽和提高服务稳定性至关重要。以下是几种有效策略&#xff1a; 1. 使用…

[spring]XML配置文件标签

spring的XML配置文件的标签大体可以分为两种&#xff1a; 其中的默认标签&#xff0c;我们前面文章里面出现的标签都是默认标签&#xff0c;是spring本身自带的&#xff0c;不需要我们去引入其他东西。而自定义标签则是指非默认标签的其他的由我们或产品发行方自定义的对接spir…

简单的bytebuddy学习笔记

简单的bytebuddy学习笔记 此笔记对应b站bytebuddy学习视频进行整理&#xff0c;此为视频地址&#xff0c;此处为具体的练习代码地址 一、简介 ByteBuddy是基于ASM (ow2.io)实现的字节码操作类库。比起ASM&#xff0c;ByteBuddy的API更加简单易用。开发者无需了解class file …

【信息系统项目管理师】高分论文:论信息系统项目的进度管理(人力资源管理系统)

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文1、规划进度管理3、排列活动顺序4、估算活动持续时间5、制订进度计划6、控制进度论文 2022年2月,我作为项目经理参与了XX电网公司人力资源管理系统建设项目,该项目是2022年XX电网公司“十三五”信息化规…

vue3项目结合Echarts实现甘特图(可拖拽、选中等操作)

效果图&#xff1a; 图一&#xff1a;选中操作 图二&#xff1a;上下左右拖拽操作 本案例在echarts​​​​​​​示例机场航班甘特图的基础上修改​​​​​​​ 封装ganttEcharts组件&#xff0c;测试数据 airport-schedule.jsonganttEcharts代码: 直接复制粘贴可测​​​​…

GIT安装过程

文章目录 ‌下载安装包‌安装过程‌验证安装‌Git的基本使用‌ ‌Git的安装可以通过以下步骤完成‌ ‌下载安装包‌ 首先&#xff0c;访问Git官网(https://git-scm.com/)或Git for Windows(https://gitforwindows.org/)下载对应系统的安装包。 对于Windows系统&#xff0c;通常…

Java 技术面试常见问题解析

1.说说Mybatis的缓存机制: MyBatis 是一个优秀的持久层框架&#xff0c;它简化了企业应用开发中数据库操作的代码。MyBatis 提供了一级缓存和二级缓存机制来优化对数据库的访问。 一级缓存 (SqlSession级别的缓存) 一级缓存是 MyBatis 中默认开启且无法关闭的缓存机制。它存…

Word使用分隔符实现页面部分分栏

文章目录 Word使用分隔符实现页面部分分栏分隔符使用页面设置 Word使用分隔符实现页面部分分栏 分隔符使用 word中的分隔符&#xff1a; 前面不分栏&#xff0c;后面分栏(或前面分栏&#xff0c;后面不分栏)&#xff0c;只需要在分隔位置处插入分隔符&#xff1a;“连续”即…

掌握 Spring Boot 中的 WebClient:何时以及为何使用它而不是 RestTemplate

在开发 Spring Boot 应用程序时&#xff0c;与 RESTful Web 服务进行通信是一项常见需求。从历史上看&#xff0c;开发人员已将RestTemplate用于此目的。然而&#xff0c;随着反应式编程的出现和对更高效资源利用的需求&#xff0c;WebClient已成为首选。本文探讨了RestTemplat…

主曲率为常数时曲面分类

主曲率为常数 ⇔ K , H \Leftrightarrow K,H ⇔K,H 为常数&#xff0c;曲面分类&#xff1a; 1.若 k 1 k 2 0 k_1k_20 k1​k2​0,则 S S S为全脐点曲面——平面的一部分&#xff1b; 2.若 k 1 k 2 ≠ 0 k_1k_2\neq0 k1​k2​0,则 S S S为全脐点曲面——球面的一部分&…

asp.net core发布配置端口号,支持linux

方式一&#xff0c;修改配置文件 appsettings.json 找到文件 appsettings.json&#xff0c; 添加如下节点配置&#xff0c;在linux环境需要设置0.0.0.0才可以正常代表本机&#xff0c;然后被其他机器访问&#xff0c;此处设置端口8000&#xff0c; "Kestrel": {&quo…

【安当产品应用案例100集】033-安当TDE透明加密在移动存储加密中的应用案例

背景介绍 随着移动互联网的普及&#xff0c;企业和个人越来越依赖移动存储设备&#xff0c;如U盘、移动硬盘以及云存储服务进行数据的存储和传输。然而&#xff0c;这种便捷性也带来了数据安全的隐患。如何确保存储在移动设备上的数据不被非法访问和泄露&#xff0c;成为企业和…

【linux 内存】cat /proc/meminfo、free

cat /proc/meminfo 各字段详解 /proc/meminfo是了解Linux系统内存使用状况的主要接口&#xff0c;我们最常用的”free”、”vmstat”等命令就是通过它获取数据的 &#xff0c;/proc/meminfo所包含的信息比”free”等命令要丰富得多&#xff0c;因此需要了解这些字段的含义。 …

Android HandlerThread、Looper、MessageQueue 源码分析

Android HandlerThread、Looper、MessageQueue 源码分析 简介 在 Android 开发中&#xff0c;大家应该对 HandlerThread 有一定了解。顾名思义&#xff0c;HandlerThread 是 Thread 的一个子类。与普通的 Thread 不同&#xff0c;Thread 通常一次只能执行一个后台任务&#x…

配置PostgreSQL用于集成测试的步骤

在进行软件开发时&#xff0c;集成测试是确保各个组件能够协同工作的关键环节。PostgreSQL作为一种强大的开源数据库系统&#xff0c;常被用于集成测试中。下面将详细介绍如何在不同的环境中配置PostgreSQL以支持集成测试。 1. 选择并安装PostgreSQL 首先&#xff0c;你需要根…

WebRTC搭建与应用(一)-ICE服务搭建

WebRTC搭建与应用(一) 近期由于项目需要在研究前端WebGL渲染转为云渲染&#xff0c;借此机会对WebRTC、ICE信令协议等有了初步了解&#xff0c;在此记录一下&#xff0c;以防遗忘。 第一章 ICE服务搭建 文章目录 WebRTC搭建与应用(一)前言一、ICE是什么&#xff1f;二、什么…