设计模式实践:模板方法、观察者与策略模式详解

目录

  • 1 模板方法
    • 1.1 模板方法基本概念
    • 1.2 实验
      • 1.2.1 未使用模板方法实现代码
      • 1.2.2 使用模板方法的代码
  • 2 观察者模式
    • 2.1 观察者模式基本概念
    • 2.2 实验
  • 3 策略模式
    • 3.1 策略模式基本概念
    • 3.2 实验

1 模板方法

1.1 模板方法基本概念

  • 定义:一个操作中的算法的骨架 ,而将一些步骤延迟到子类中。 Template Method使得子类可以不
    改变一个算法的结构即可重定义该算法的某些特定步骤。
  • 要点:
    • 最常用的设计模式,子类可以复写父类子流程,使父类的骨架流程丰富
    • 父类 protected 保护子类需要复写的子流程;这样子类的子流程只能父类来调用

1.2 实验

背景
某个品牌动物园,有一套固定的表演流程,但是其中有若干个表演子流程可创新替换,以尝试迭代更新表演流程;

1.2.1 未使用模板方法实现代码

#include <iostream>
using namespace std;#if 0
class ZooShow {
public:void Show0() {cout << "show0" << endl;}void Show2() {cout << "show2" << endl;}
};class ZooShowEx {
public:void Show1() {cout << "show1" << endl;}void Show3() {cout << "show3" << endl;}
};// 不满足单一职责 , 开 扩展 修改闭原则
// 动物园固定流程,迭代创新
// 稳定和变化   一定的方向上变化
#else if 2
class ZooShow {
public:ZooShow(int type = 1) : _type(type) {}public:void Show() {if (Show0())PlayGame(); // 里氏替换Show1();Show2();Show3();}// 接口隔离 不要让用户去选择它们不需要的接口
private:void PlayGame() {cout << "after Show0, then play game" << endl;}private:bool Show0() {cout << _type << " show0" << endl;return true;}void Show1() {if (_type == 1) {cout << _type << " Show1" << endl;} else if (_type == 2) {cout << _type << " Show1" << endl;} else if (_type == 3) {}}void Show2() {if (_type == 20) {}cout << "base Show2" << endl;}void Show3() {if (_type == 1) {cout << _type << " Show1" << endl;} else if (_type == 2) {cout << _type << " Show1" << endl;}}
private:int _type;
};#endifint main () {
#if 0ZooShow *zs = new ZooShow;ZooShowEx *zs1 = new ZooShowEx;zs->Show0();zs1->Show1();zs->Show2();zs1->Show3();
#else if 2ZooShow *zs = new ZooShow(1);zs->Show();
#endifreturn 0;
}

分析:

  • 1.缺乏可扩展性
    在当前代码里,ZooShow 类的 Show 方法内包含了很多 if - else 条件判断,用来依据不同的 _type 值执行不同的逻辑。要是需要新增一种表演类型,就得修改 Show 方法,添加新的 if - else 分支。这违背了开闭原则(对扩展开放,对修改关闭),代码的可扩展性较差。例如,如果要增加 _type == 4 的表演流程,就得在各个方法里添加对应的判断逻辑。
  • 2.代码复用性低
    每个表演类型的逻辑都被硬编码在 ZooShow 类的各个方法中,不同表演类型之间的公共逻辑没有得到很好的复用。如果某些表演类型有相似的流程,当前代码无法有效复用这些公共部分,会造成代码冗余。
  • 3.违反单一职责原则
    ZooShow 类承担了过多的职责,它不仅定义了表演的流程,还包含了每种表演类型的具体逻辑**。当表演类型增多或者表演流程发生变化时,这个类会变得越来越复杂,难以维护**。
  • 4.可读性和可维护性差
    大量的 if - else 条件判断使得代码的逻辑变得复杂,降低了代码的可读性。而且,当需要修改或添加新的表演类型时,需要在多个方法中查找和修改相关逻辑,增加了维护的难度。

1.2.2 使用模板方法的代码

学习设计模式 我们可以通过这些 要点

  • 定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法。
  • 解决的问题
    确定点:算法骨架
    变化点:子流程需要变化
  • 代码结构
    基类中存骨架流程接口
    所有子流程对子类开放并且是虚函数
    多态使用方式
  • 符合哪些设计原则
    单一职责
    开闭
    依赖倒置:子类扩展时,需要依赖基类的虚函数实现;使用者只依赖接口
    封装变化点:protected
    接口隔离
    最小知道原则
  • 如何扩展
    实现子类继承基类,重写子流程
    通过多态调用方式使用
#include <iostream>
using namespace std;// 抽象基类,定义表演流程的模板
class ZooShowTemplate {
public:// 模板方法,定义表演的整体流程void Show() {if (Show0())PlayGame();Show1();Show2();Show3();}virtual ~ZooShowTemplate() {}protected:// 具体步骤的虚函数,可在子类中重写virtual bool Show0() {cout << "show0" << endl;return true;}virtual void PlayGame() {cout << "after Show0, then play game" << endl;}virtual void Show1() = 0;virtual void Show2() = 0;virtual void Show3() = 0;
};// 具体表演类型 1
class ZooShowType1 : public ZooShowTemplate {
protected:void Show1() override {cout << "1 Show1" << endl;}void Show2() override {cout << "base Show2" << endl;}void Show3() override {cout << "1 Show3" << endl;}
};// 具体表演类型 2
class ZooShowType2 : public ZooShowTemplate {
protected:void Show1() override {cout << "2 Show1" << endl;}void Show2() override {cout << "base Show2" << endl;}void Show3() override {cout << "2 Show3" << endl;}
};int main() {ZooShowTemplate* zs1 = new ZooShowType1();zs1->Show();ZooShowTemplate* zs2 = new ZooShowType2();zs2->Show();delete zs1;delete zs2;return 0;
}

解决的问题

  • 确定点(算法骨架):代码里 ZooShowTemplate 类的 Show 方法确定了表演流程这个算法骨架,固定了表演的整体执行顺序。
  • 变化点(子流程需要变化):不同类型的表演,如 ZooShowType1 和 ZooShowType2,它们的 Show1、Show2、Show3 具体实现是不同的,这就是子流程的变化点,通过继承基类并重写相应虚函数来实现不同的子流程

代码结构

  • 基类中存骨架流程接口:ZooShowTemplate 类中定义的 Show 方法就是骨架流程接口,它包含了整个表演流程的逻辑。
  • 所有子流程对子类开放并且是虚函数:Show0、PlayGame、Show1、Show2、Show3 这些子流程方法在 ZooShowTemplate 类中都被定义为虚函数,方便子类重写,实现不同的子流程逻辑。
  • 多态使用方式:在 main 函数中,通过基类指针 ZooShowTemplate* 分别指向 ZooShowType1 和 ZooShowType2 的对象,然后调用 Show 方法,运行时根据实际指向的子类对象调用相应子类重写的方法,体现了多态性。

符合的设计原则

  • 单一职责:ZooShowTemplate 类负责定义表演流程骨架,各个子类负责具体表演类型的子流程实现,职责划分清晰 ,每个类只专注于自己的职责。
  • 开闭:当需要新增一种表演类型时,如 ZooShowType3,只需创建一个新类继承 ZooShowTemplate 并重写相关虚函数,不需要修改 ZooShowTemplate 类的代码,对扩展开放,对修改关闭。
  • 依赖倒置:子类扩展时依赖基类的虚函数实现,比如 ZooShowType1 和 ZooShowType2 依赖 ZooShowTemplate 中定义的虚函数;使用者(main 函数)只依赖 ZooShowTemplate 这个抽象基类接口,而不是具体子类,降低了耦合度。
  • 封装变化点:在 ZooShowTemplate 类中,将一些可能变化的子流程方法(如 Show1、Show2 等)定义为虚函数,并且访问修饰符为 protected,对外部隐藏了具体实现细节,同时方便子类重写来实现变化。
  • 接口隔离:虽然代码中未明显体现接口隔离的典型场景,但从某种程度上,每个子类只实现自己需要的虚函数,没有被迫依赖不需要的接口方法。
  • 最小知道原则:子类只需要了解与自己相关的基类虚函数,不需要了解基类中其他不必要的实现细节,减少了类之间的信息交互。

如何扩展

  • 实现子类继承基类,重写子流程:如代码中 ZooShowType1 和 ZooShowType2 继承自 ZooShowTemplate,并重写了 Show1、Show2、Show3 等子流程方法,实现不同表演类型的定制。
  • 通过多态调用方式使用:在 main 函数中,通过基类指针调用 Show 方法,利用多态性根据实际子类对象调用相应的重写方法,实现不同表演类型的流程执行。

2 观察者模式

2.1 观察者模式基本概念

  • 定义:对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新
  • 特性
    • 松耦合:主题和观察者相互独立,主题无需知道观察者具体细节,只知其实现了观察者接口 。比如电商系统中商品信息(主题)变化,不同的展示模块(观察者)可独立更新,互不干扰。
    • 动态性:观察者可随时添加或移除,不影响系统其他部分 。例如新闻推送系统,新用户(观察者)可随时订阅(添加)或退订(移除)频道(主题)。

2.2 实验

背景:
气象站发布气象资料给数据中心,数据中心经过处理,将气象信息更新到两个不同的显示终端(A和B)
实现伪代码

#include <vector>//
class IDisplay {
public:virtual void Show(float temperature) = 0;virtual ~IDisplay() {}
};class DisplayA : public IDisplay {
public:virtual void Show(float temperature);
private:void jianyi();
};class DisplayB : public IDisplay{
public:virtual void Show(float temperature);
};class DisplayC : public IDisplay{
public:virtual void Show(float temperature);
};class WeatherData {
};class DataCenter {
public:void Attach(IDisplay * ob);void Detach(IDisplay * ob);void Notify() {float temper = CalcTemperature();for (auto iter = obs.begin(); iter != obs.end(); iter++) {(*iter)->Show(temper);}}// 接口隔离
private:virtual WeatherData * GetWeatherData();virtual float CalcTemperature() {WeatherData * data = GetWeatherData();// ...float temper/* = */;return temper;}std::vector<IDisplay*> obs;
};int main() {DataCenter *center = new DataCenter;IDisplay *da = new DisplayA();IDisplay *db = new DisplayB();IDisplay *dc = new DisplayC();center->Attach(da);center->Attach(db);center->Attach(dc);center->Notify();//-----center->Detach(db);center->Notify();return 0;
}

定义与解决的问题

  • 定义体现:观察者模式定义对象间一对多依赖关系,代码中 DataCenter 类相当于主题(被观察者),IDisplay 及其派生类**(DisplayA、DisplayB、DisplayC )相当于观察者** 。DataCenter 维护着多个 IDisplay 指针(观察者),当温度数据计算出来(主题状态变化)时,通知所有注册的观察者,符合一对多依赖关系的定义。
  • 稳定点与变化点
    • 稳定点:“一” 对应的是 DataCenter 类,它是主题,在系统中相对稳定,负责管理观察者和通知逻辑。
    • 变化点:“多” 对应的是 IDisplay 的不同派生类实例,如 DisplayA、DisplayB、DisplayC ,可以随时增加新的显示类(“多” 增加 ),或者移除已有的显示类(“多” 减少 ),比如在 main 函数中通过 Attach 和 Detach 方法进行添加和移除操作。

代码结构
-代码定义了主题类 DataCenter ,通过 std::vector<IDisplay*> 来存储观察者。观察者通过抽象接口 IDisplay 定义,具体观察者类 DisplayA、DisplayB、DisplayC 实现该接口。DataCenter 有 Attach、Detach 方法管理观察者,Notify 方法用于通知观察者。结构上满足观察者模式中主题与观察者的基本组织形式。
符合的设计原则

  • 面向接口编程:代码中定义了抽象接口 IDisplay ,DataCenter 类依赖 IDisplay 接口来管理观察者,而不是具体的观察者类(如 DisplayA、DisplayB 等 )。例如 DataCenter 的 Attach 方法接收 IDisplay * 类型参数,体现了面向接口编程,降低了耦合度。
  • 接口隔离:IDisplay 接口只定义了 Show 方法,每个具体的显示类只需要实现这个与自身显示功能相关的方法,没有被迫实现不必要的接口方法。并且 DataCenter 类内部也有一些方法(如 GetWeatherData 等 )相对隔离,符合接口隔离原则。
  • 封装变化点
    attach:在代码中对应 Attach 方法,用于将观察者(IDisplay 的派生类实例 )添加到 DataCenter 的观察者列表中,封装了增加观察者这个变化点。
    detach:对应 Detach 方法,用于从观察者列表中移除观察者,封装了减少观察者这个变化点。

如何扩展

若要扩展系统,比如增加新的显示方式(新的观察者 ),可以创建一个新的类继承自 IDisplay ,实现 Show 方法,然后在 main 函数中通过 DataCenter 的 Attach 方法将其添加到观察者列表中,就能参与到温度数据的显示通知流程中。

3 策略模式

3.1 策略模式基本概念

定义与核心思想

  • 定义一系列算法:把相关算法进行归纳整理,形成一个算法集合。比如电商系统中计算商品折扣,有固定折扣、满减折扣、会员专属折扣等不同算法 。
  • 封装每个算法:将每个算法独立封装在对应的策略类中。以支付场景为例,支付宝支付、微信支付、银行卡支付等,每种支付方式的实现细节都封装在各自的策略类里,外部无需了解具体支付流程(如网络请求、加密处理等 )。
  • 算法可相互替换:在运行时,可根据实际情况灵活切换不同策略,而不影响使用算法的客户端。例如地图导航,用户可在 “最短距离”“最快速度”“避开拥堵” 等不同路径规划策略间切换 。
    组成部分
  • 策略接口(抽象策略角色):定义算法的公共接口,规定算法应具备的方法签名。比如定义一个计算税费的策略接口,其中包含计算税费的抽象方法 calculateTax() 。
  • 具体策略类:实现策略接口,提供具体算法的实现。如上述计算税费的场景,有针对不同地区税率计算税费的具体策略类,像 “北京地区税费计算类”“上海地区税费计算类” 等,分别实现 calculateTax() 方法。
  • 上下文类:持有策略接口的引用,负责在合适时机调用策略对象的算法。例如电商系统中结算模块作为上下文类,它持有税费计算策略接口的引用,在结算时调用具体策略类(如根据收货地区选择对应地区的税费计算策略 )来计算税费。

3.2 实验

背景:某商场节假日有固定促销活动,为了加大促销力度,现提升国庆节促销活动规格
实现

class Context {};class ProStategy {
public:virtual double CalcPro(const Context &ctx) = 0;virtual ~ProStategy(); 
};
// cpp
class VAC_Spring : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_QiXi : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};
class VAC_QiXi1  : public VAC_QiXi {
public:virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_Wuyi : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_GuoQing : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};class VAC_Shengdan : public ProStategy {
public:virtual double CalcPro(const Context &ctx){}
};class Promotion {
public:Promotion(ProStategy *sss) : s(sss){}~Promotion(){}double CalcPromotion(const Context &ctx){return s->CalcPro(ctx);}
private:ProStategy *s;
};int main () {Context ctx;ProStategy *s = new VAC_QiXi1();Promotion *p = new Promotion(s);p->CalcPromotion(ctx);return 0;
}

解决的问题

  • 稳定点:在该商场促销场景中,“客户端与算法的调用关系” 是稳定点。从代码看,Promotion 类(客户端)通过构造函数接收 ProStategy 指针(算法相关),并在 CalcPromotion 方法中固定地调用 s->CalcPro(ctx) 来执行促销算法,这种调用关系相对稳定。
  • 变化点
    • 新加算法:当商场要增加新的促销活动时,比如后续可能新增某个节日的促销策略,就需要添加新的具体策略类。像代码中如果要新增 “元旦促销策略”,可以创建新类继承自 ProStategy 并实现 CalcPro 方法。
    • 算法内容改变:已有的促销策略(如 VAC_QiXi 等类 ),其内部的促销计算逻辑(CalcPro 方法的实现 )可能会根据商场需求进行调整和改变。
      代码结构
      定义了抽象策略类 ProStategy ,其中声明了纯虚函数 CalcPro ,用于定义促销算法的接口。一系列具体策略类(VAC_Spring、VAC_QiXi 等 )继承自 ProStategy ,并实现 CalcPro 方法,各自代表不同节日的促销算法。Context 类目前为空,但在策略模式中通常用于存储上下文相关信息,供策略类使用。
      Promotion 类作为上下文类,持有 ProStategy 指针,通过构造函数进行依赖注入(接收具体的策略对象 ),并在 CalcPromotion 方法中调用策略对象的 CalcPro 方法来执行促销计算。

设计原则

  • 接口隔离
    • 依赖注入:Promotion 类通过构造函数 Promotion(ProStategy *sss) 将具体的促销策略对象注入进来,实现了类与具体策略的解耦。比如在 main 函数中可以灵活地将不同的 ProStategy 子类对象(VAC_QiXi1 等 )注入到 Promotion 中。
    • 解决通过一个接口解决两个类的依赖:ProStategy 接口将 Promotion 类和具体的促销策略类(如 VAC_QiXi 等 )解耦,使得 Promotion 类只依赖于抽象接口,而不依赖具体策略类的实现细节,解决了它们之间的依赖问题。
  • 面向接口编程:整个代码围绕 ProStategy 接口展开,Promotion 类依赖 ProStategy 接口,而不是具体的策略类。在 main 函数中也是通过 ProStategy 指针来操作具体的策略对象,体现了面向接口编程,降低了代码间的耦合度。
  • 开闭原则:当需要新增促销策略(如新增节日促销 )时,只需创建新的类继承 ProStategy 并实现 CalcPro 方法,无需修改现有的 Promotion 类以及其他已有的策略类代码,对扩展开放,对修改关闭。
    其实还有一个组合优于继承的原则

如何扩展代码
若要扩展代码,比如增加新的促销策略,只需创建一个新的类继承自 ProStategy ,并实现 CalcPro 方法。然后在 main 函数中,创建该新策略类的对象,并将其注入到 Promotion 类中,即可使用新的促销策略。例如新增 “中秋促销策略”,可以编写一个新类继承 ProStategy ,实现 CalcPro 方法来定义中秋促销的计算逻辑,然后在 main 函数中按现有方式使用这个新策略。
怎么调用

 ProStategy *s = new VAC_QiXi1();Promotion *p = new Promotion(s);p->CalcPromotion(ctx);

多态调用

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

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

相关文章

Vue 2.0和3.0笔记

Vue 3 关于组件 今天回顾了下2.0关于组件的内容&#xff0c;3.0定义组件的方式多了一种就是通过单文件组件&#xff08;Single-File Component&#xff09;的方式将Vue的模板&#xff0c;逻辑和样式放到一个文件中&#xff0c;2.0则不同&#xff0c;它是将模板放到一个属性中…

前端面试-微前端

1. 什么是微前端&#xff1f;它的核心价值是什么&#xff1f; 答案&#xff1a; 微前端是一种将前端应用拆分为独立模块的架构模式&#xff0c;每个模块可由不同团队独立开发、测试、部署和运行。其核心价值包括&#xff1a; 技术栈无关性&#xff1a;支持 React、Vue、Angul…

Axure高保真AI算法训练平台

点击下载《Axure高保真AI算法训练平台(.rp) 》 原型效果&#xff1a;https://axhub.im/ax9/69fdf8f2b10b59c3/#g1 摘要 本文介绍了一款功能全面且高效的AI算法训练平台&#xff0c;旨在为数据科学家、研究人员和工程师提供从数据准备到模型部署的一站式解决方案。该平台由四大…

Ubuntu服务器日志满audit:backlog limit exceeded了会报错解决方案-Linux 审计系统 (auditd) 工具

auditd 是 Linux 系统中的审计守护进程&#xff0c;负责收集、记录和监控系统安全相关事件。以下是相关工具及其功能&#xff1a; 核心组件 auditd - 审计守护进程 系统的审计服务主程序 收集系统调用信息并写入日志文件 通常存储在 /var/log/audit/audit.log auditctl - 审计控…

Windows10系统RabbitMQ无法访问Web端界面

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 项目场景&#xff1a; 在一个基于 .NET 的分布式项目中&#xff0c;团队使用 RabbitMQ 作为消息队列中间件&#xff0c;负责模块间的异步通信。开发环境为 Windows 10 系统&#xff0c;开发人员按照官…

Qt 的 事件队列

Qt 的 事件队列 是其核心事件处理机制之一&#xff0c;用于管理和分发系统与用户生成的事件&#xff08;如鼠标点击、键盘输入、定时器、信号槽中的队列连接等&#xff09;。理解 Qt 的事件队列对多线程、界面响应以及异步处理尤为关键。 一、Qt 的事件处理模型概览 Qt 是基于…

无人机自主导航与路径规划技术要点!

一、自主导航与路径规划技术要点 1. 传感器融合 GPS/北斗定位&#xff1a;提供全局定位&#xff0c;但在室内或遮挡环境下易失效。 惯性测量单元&#xff08;IMU&#xff09;**&#xff1a;通过加速度计和陀螺仪实时追踪姿态&#xff0c;弥补GPS信号丢失时的定位空缺。 …

Before After:SQL整容级优化

首先说明这个优化有一定提升&#xff0c;但不是我所期望的 我接到一个涉及优化的SQL&#xff0c;具体内容实在太长。而且可能也不利于阅读。于是我脱敏以及简化一下。SQL中间大量的充斥着 (select 列名1 from t1 where t1.id t2.id ) A, (select 列名2 from t1 where t1.id …

道可云人工智能每日资讯|首届世界人工智能电影节在法国尼斯举行

道可云元宇宙每日简报&#xff08;2025年4月15日&#xff09;讯&#xff0c;今日元宇宙新鲜事有&#xff1a; 杭州《西湖区打造元宇宙产业高地的扶持意见》发布 杭州西湖区人民政府印发《西湖区打造元宇宙产业高地的扶持意见》。该意见已于4月4日正式施行&#xff0c;有效期至…

JVM 为什么需要即时编译器?

JVM之所以需要即时编译器 (JIT Compiler)&#xff0c;是为了提高 Java 程序的执行性能&#xff0c;弥补纯解释器执行的不足。 我们可以从以下几个角度来分析一下这个问题&#xff1a; 1. 解释器的性能瓶颈: 逐条解释的开销: 解释器需要逐条读取 Java 字节码指令&#xff0c;并…

PromptUp 网站介绍:AI助力,轻松创作

1. 网站定位与核心功能 promptup.net 可能是一个面向 创作者、设计师、营销人员及艺术爱好者 的AI辅助创作平台,主打 零门槛、智能化的内容生成与优化。其核心功能可能包括: AI艺术创作:通过输入关键词、选择主题或拖放模板,快速生成风格多样的数字艺术作品(如插画、海报…

ThingsBoard3.9.1 MQTT Topic(1)

1.网关转发子设备的遥测信息, Topic:v1/gateway/telemetry { "m1": [{ "mode": "CW", "temperature": 23 }], "m2": [{ "mode": "CW", "temperature": 23 }] } 说明&#xff1a;json格式&a…

React 入门教程:构建第一个 React 应用

本教程将带你从零开始构建你的第一个 React 应用。我们将创建一个简单的计数器应用&#xff0c;涵盖 React 的基本概念和开发流程。 准备工作 在开始之前&#xff0c;请确保你的开发环境满足以下要求&#xff1a; Node.js (建议使用最新的 LTS 版本) npm 或 yarn (Node.js 安…

vue3中,element-plus中el-input的v-model和value的用法示例

el-input的v-model&#xff0c;邦定响应式变量 <el-col :span"6"><el-form-item label"检验类别" prop"verifyType"><el-input v-model"applyAllInfo.applyBasicInfo.verifyTypeName" readonly /></el-form-item…

策略模式随笔~

若感行文枯燥&#xff0c;请移步至文末Gitee地址中查看源码自行测试感受策略模式之魅力。 一、策略模式的核心概念 策略模式的定义 定义算法族&#xff0c;封装每个算法&#xff0c;使其可互换。 核心三要素 Context&#xff1a;上下文&#xff0c;负责接收客户端请求并委托…

Linux的目录结构(介绍,具体目录结构)

目录 介绍 具体目录结构 简洁的目录解释 详细的目录解释 介绍 Linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构的最上层是根目录“/”。Linux的世界中&#xff0c;一切皆文件&#xff08;比如&#xff1a;Linux会把硬件映射成文件来管理&#xff09; 具体目…

AWS CloudFront加速S3配置跨域

1、点击分配 源我们就选择S3–>选择我们要加速的S3存储桶 2、创建OAC访问方式 在我们的来源访问处–>来源访问控制设置(推荐)–>选择创建新的OAC(Create new OAC)–>自定义名字按默认选项保存–>选择刚刚新创建的OAC 3、选择查看器的配置 根据具体情况&#x…

进程控制(上)【Linux操作系统】

进程控制 写时拷贝 本质是一种减少深拷贝的方法 Linux中有很多拷贝的场景都用得上写时拷贝&#xff0c;下面以创建子进程时的写时拷贝为例&#xff1a; 子进程被创建的时候&#xff1a; 会继承父进程的mm_struct和页表 所以子进程刚刚继承时&#xff0c;父子进程的代码和数据…

Flutter 强制横屏

在 Flutter 中&#xff0c;可以通过设置 SystemChrome 来强制应用横屏显示。以下是实现这一功能的详细步骤和代码示例&#xff1a; 步骤 1&#xff1a;导入必要的包 确保在文件顶部导入了 services.dart 包&#xff0c;因为 SystemChrome 类位于该包中。 import package:flut…

Git完全指南:从入门到精通版本控制 ------- Git核心命令(6)

Git核心命令完全指南&#xff1a;从入门到高效协作 前言 在软件开发领域&#xff0c;Git已成为现代版本控制的代名词。据统计&#xff0c;全球超过90%的开发团队使用Git进行代码管理。然而&#xff0c;许多开发者仅停留在基础命令的机械使用层面&#xff0c;未能真正掌握Git命…