当前位置: 首页 > news >正文

设计模式4-模版方法

设计模式

  • 重构获得模式
  • 重构的关键技法
      • 1. 静态转动态
      • 2. 早绑定转晚绑定
      • 3. 继承转组合
      • 4. 编译时依赖转运行时依赖
      • 5. 紧耦合转松耦合
  • 组件协助
    • 动机
    • 模式定义
      • 结构
    • 要点总结。
  • 例子
      • 示例解释:

重构获得模式

设计模式的目的是应对变化,提高复用

设计模式的要点是寻找变化点,然后在变化点处应用设计模式。从而更好地应对需求的变化。什么时候什么地点应用设计模式。比设计模式结构本身更为重要。
设计模式的应用,不应当先入为主,一上来就套用设计模式这是设计模式的最大误用,没有一步到位的设计。敏捷软件开发实践提倡的是refacroring to Patterns(重构), 是目前普遍公认的最好使用的设计模式的方法。

推荐书籍

在这里插入图片描述

重构的关键技法

让变化可配置
重构是改善现有代码设计的过程,通过一系列的技术手法和策略,使得代码更易于理解、扩展和维护。以下是几种重构的关键技法,以及它们在代码中的应用示例:

1. 静态转动态

技法说明

  • 将在编译时确定的部分改为在运行时确定,增加代码的灵活性和适应性。

示例

  • 将硬编码的条件判断改为通过配置文件或者用户输入来确定。
// 静态
bool isFeatureEnabled() {return true;  // 静态确定特性总是启用
}// 动态
bool isFeatureEnabled() {// 通过配置文件或者用户输入来确定特性是否启用return config.isEnabled("featureX");
}

2. 早绑定转晚绑定

技法说明

  • 将函数调用的绑定从编译时确定延迟到运行时,使得对象能够在运行时选择调用不同的方法或策略。

示例

  • 使用虚函数和多态来实现晚绑定,而不是通过静态绑定的方式。
// 早绑定
class Shape {
public:void draw() {// 绘制代码}
};// 晚绑定
class Shape {
public:virtual void draw() {// 绘制代码}
};class Circle : public Shape {
public:void draw() override {// 绘制圆形的代码}
};class Rectangle : public Shape {
public:void draw() override {// 绘制矩形的代码}
};void render(Shape* shape) {shape->draw();  // 晚绑定,根据实际对象类型调用对应的draw方法
}

3. 继承转组合

技法说明

  • 通过组合现有类的实例来代替继承,以减少类之间的耦合性,同时提高代码的灵活性和可维护性。

示例

  • 将继承关系改为对象组合关系。
// 继承
class Car {
public:virtual void drive() {// 驾驶汽车}
};class SportsCar : public Car {
public:void drive() override {// 驾驶运动汽车}
};// 组合
class Engine {
public:void start() {// 启动引擎}
};class Car {
private:Engine engine;public:void drive() {engine.start();// 驾驶汽车}
};class SportsCar {
private:Engine engine;public:void drive() {engine.start();// 驾驶运动汽车}
};

4. 编译时依赖转运行时依赖

技法说明

  • 将程序依赖关系从编译时硬编码转为运行时根据条件动态确定,提高程序的灵活性和可配置性

示例

  • 使用依赖注入或者配置来动态确定依赖。
// 编译时依赖
class Database {
public:void saveData(const std::string& data) {// 保存数据到 MySQL 数据库}
};// 运行时依赖
class Database {
public:virtual void saveData(const std::string& data) = 0;
};class MySQLDatabase : public Database {
public:void saveData(const std::string& data) override {// 保存数据到 MySQL 数据库}
};class PostgresDatabase : public Database {
public:void saveData(const std::string& data) override {// 保存数据到 PostgreSQL 数据库}
};void saveData(Database* db, const std::string& data) {db->saveData(data);  // 根据运行时传入的数据库对象调用相应的方法
}

5. 紧耦合转松耦合

技法说明

  • 减少模块或者类之间的依赖关系,使得各个模块之间可以独立开发、测试和部署。

示例

  • 使用依赖注入、接口抽象等手段降低模块间的耦合度。
// 紧耦合
class ServiceA {
public:void doSomething() {ServiceB b;b.doSomethingElse();}
};class ServiceB {
public:void doSomethingElse() {// 实现}
};// 松耦合
class ServiceB {
public:void doSomethingElse() {// 实现}
};class ServiceA {
private:ServiceB& b;public:ServiceA(ServiceB& b) : b(b) {}void doSomething() {b.doSomethingElse();}
};

通过这些关键技法,可以更好地进行代码重构,改进现有设计,使得代码更易于维护、扩展和重用,同时提高系统的灵活性和可靠性。

组件协助

定义:现代软件分专业分工之后的第一个结果是框架与应用的区分组建协作模式,通过完绑定来实现框架与应用间的松耦合是二者之间协作时常用的模式。

典型模式
• Template Method
• Observer / Event
• Strategy

动机

在软件构建过程中,每一项任务它常常有稳定的整体操作结构。但各个子步骤却有很多变化的需求。或者由于固定的原因,比如框架与应用之间的关系。而无法和任务的整体结构同时实现。
如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚七实现需求?

结构化软件设计流程

在这里插入图片描述

面向对象软件设计流程

在这里插入图片描述

早绑定与晚绑定

在这里插入图片描述

模式定义

定义一个操作中的算法框架(稳定),而将一些步骤延迟(变化)到子类中template Method 使得子类可以不改变。一个算法的结构即可重新定义就是重写该算法的某些特定步骤。

结构

在这里插入图片描述

要点总结。

模板方法模式是一种非常基础性的设计模式。在面向对象系统中有着大量的应用。他用最简洁的机制也就是虚函数的多态性。为很多应用程序架构提供了灵活的扩展点。是代码复用方面的基本实现结构

除了可以灵活应对自步骤的变化以外,不要调用我,让我来调用你。反向控制结构是模板方法的典型应用。

在具体实验方面,被模板方法调用的虚方法可以具有实现,也可以没有任何实现。也就是所谓的抽象方法和纯虚方法。但一般推荐将他们设置为保护方法

例子

Template Method(模板方法)模式是一种行为设计模式,定义了一个操作中的算法的框架,将一些步骤推迟到子类中实现。这种模式是通过创建一个模板方法,该方法在一个算法的结构中定义了算法的骨架,而将一些步骤的实现延迟到子类中。

以下是一个简单的 C++ 示例,演示了模板方法模式的实现:

#include <iostream>// 抽象基类
class AbstractClass {
public:// 模板方法,定义了算法的骨架void templateMethod() {operation1();commonOperation(); // 模板方法中可以包含具体实现operation2();if (hookMethod()) { // 钩子方法,可选覆盖optionalOperation();}}protected:// 纯虚函数,需要在子类中实现virtual void operation1() = 0;virtual void operation2() = 0;// 具体方法,子类共享的实现void commonOperation() {std::cout << "AbstractClass: commonOperation" << std::endl;}// 钩子方法,可选覆盖virtual bool hookMethod() {return true; // 默认实现}// 可选的具体方法,子类可以选择性地覆盖virtual void optionalOperation() {std::cout << "AbstractClass: optionalOperation" << std::endl;}
};// 具体子类实现
class ConcreteClass1 : public AbstractClass {
protected:void operation1() override {std::cout << "ConcreteClass1: operation1" << std::endl;}void operation2() override {std::cout << "ConcreteClass1: operation2" << std::endl;}bool hookMethod() override {std::cout << "ConcreteClass1: hookMethod" << std::endl;return false; // 覆盖钩子方法}
};// 另一个具体子类
class ConcreteClass2 : public AbstractClass {
protected:void operation1() override {std::cout << "ConcreteClass2: operation1" << std::endl;}void operation2() override {std::cout << "ConcreteClass2: operation2" << std::endl;}// 这里没有覆盖钩子方法
};// 客户端代码
int main() {AbstractClass* object1 = new ConcreteClass1();AbstractClass* object2 = new ConcreteClass2();// 调用模板方法,执行算法object1->templateMethod();std::cout << std::endl;object2->templateMethod();delete object1;delete object2;return 0;
}

示例解释:

  1. AbstractClass 是抽象基类,定义了模板方法 templateMethod() 和一些具体方法 commonOperation()optionalOperation(),以及一个钩子方法 hookMethod()

  2. ConcreteClass1ConcreteClass2 是具体子类,分别实现了抽象类中的纯虚函数 operation1()operation2(),并选择性地覆盖了钩子方法 hookMethod()

  3. 在客户端代码中,创建了 ConcreteClass1ConcreteClass2 的对象,并调用它们的 templateMethod() 方法,执行了定义好的算法。

  4. 输出结果展示了每个步骤的执行顺序,包括了钩子方法的选择性覆盖情况。

这个例子展示了模板方法模式的核心思想:定义一个算法的骨架,将特定的步骤延迟到子类中去实现,从而在不同的子类中实现算法的不同部分,同时保持算法结构的稳定性。

相关文章:

设计模式4-模版方法

设计模式 重构获得模式重构的关键技法1. 静态转动态2. 早绑定转晚绑定3. 继承转组合4. 编译时依赖转运行时依赖5. 紧耦合转松耦合 组件协助动机模式定义结构 要点总结。 例子示例解释&#xff1a; 重构获得模式 设计模式的目的是应对变化&#xff0c;提高复用 设计模式的要点…...

yii2 ActiveForm使用技巧

持续更新&#xff1a; 1、搜索输入框&#xff1a;form-inline <?php $form ActiveForm::begin([action > [index],method > get,options > [class > form-inline] &#xff08;增加此行代码&#xff09; ]); ?>...

【面试】基本数据类型的包装类缓存

目录 1. 说明2. Integer类分析2.1 代码块2.2 字节码2.3 分析2.4 valueOf方法 1. 说明 1.在java中&#xff0c;基本数据类型的包装类&#xff08;Integer、Byte、Character、Short、Long、Boolean&#xff09;的某些值会被缓存。2.以提高性能并减少内存使用。3.这种缓存机制是自…...

6月20日(周四)A股行情总结:A股险守3000点,恒生科技指数跌1.6%

A股三大股指走弱&#xff0c;科创板逆势上扬&#xff0c;半导体板块走强&#xff0c;多股20CM涨停。中芯国际港股涨超1%。恒生科技指数跌超1%。离岸人民币对美元汇率小幅走低&#xff0c;20日盘中最低跌至7.2874&#xff0c;创下2023年11月中旬以来的新低&#xff0c;随后收复部…...

Parallels Desktop 19 for mac破解版安装激活使用指南

Parallels Desktop 19 for Mac 乃是一款适配于 Mac 的虚拟化软件。它能让您在 Mac 计算机上同时运行多个操作系统。您可借此创建虚拟机&#xff0c;并于其中装设不同的操作系统&#xff0c;如 Windows、Linux 或 macOS。使用 Parallels Desktop 19 mac 版时&#xff0c;您可在 …...

JExcel API使用笔记

JExcel API使用笔记 JExcel是一个开源的支持excel的java类库&#xff0c;广泛利用其api来生成excel报表 API基本使用 1.创建excel文件 workbook Workbook.createWorkbook(file);//传入file文件2.创建sheet页 WritableSheet sheet workbook.createSheet("记录表&quo…...

springCloudAlibaba之分布式网关组件---gateway

gateway-网关 网关spring cloud gatewaygateway初体验gateway整合nacos简写方式 内置路由断言工厂内置断言工厂 自定义路由断言工厂自定义路由工厂 内置/自定义过滤器典型内置过滤器自定义过滤器 全局过滤器自定义全局过滤器 请求日志记录&跨域处理Gateway跨域配置&#xf…...

Springboot项目jar加密

部署的程序进行加密&#xff0c;防止第三方非法拷贝走项目进行二次开发或部署。我们知道java代码编译后生成的以.class结尾的字节码文件或者.jar/.war结尾的可执行文件都是可以反编译生成.java文件的&#xff0c;虽然反编译后生成的.java文件和原本的.java文件有些微差别&#…...

【React】高阶组件

概述 高阶组件并非一个组件&#xff0c;而是增强组件功能的一个函数。 高阶组件的作用是对多个组件公共逻辑进行横向抽离。 高阶组件 – React (reactjs.org) 示例 ChildCom1.jsx import React from react;function ChildCom1(props) {return (<div>这是子组件1<d…...

全面理解-Flutter(万字长文,深度解析)

1、Web 性能差&#xff0c;跟原生 App 存在肉眼可见的差距&#xff1b; 2、React Native 跟 Web 相比&#xff0c;支持的能力非常有限&#xff0c;特定长场景问题&#xff0c;需要三端团队一个一个处理&#xff1b; 3、Web 浏览器的安卓碎片化严重&#xff08;感谢 X5&#x…...

RabbitMQ实战宝典:从新手到专家的全面探索

前言 在当今分布式系统架构中&#xff0c;消息队列已成为不可或缺的一部分&#xff0c;而RabbitMQ作为其中的佼佼者&#xff0c;凭借其强大的功能和灵活性&#xff0c;广泛应用于各种规模的应用场景中。本文将带你从基础概念出发&#xff0c;深入探讨RabbitMQ的核心特性&#…...

6月21日(周五)AH股总结:沪指失守3000点,恒生科技指数跌近2%,多只沪深300ETF午后量能显著放大

内容提要 沪指全天围绕3000点关口来回拉锯&#xff0c;收盘跌破3000点。白酒及光刻机概念集体走低&#xff0c;中芯国际港股跌超2%。CRO医药概念及水利股逆势走强。 A股低开低走 沪指全天围绕3000点关口来回拉锯&#xff0c;收盘跌破3000点&#xff0c;跌0.24%。深成指跌0.04…...

双非本,3年时间从外包到阿里P6(Android岗),看我是怎么逆袭成功的?

而在小公司&#xff0c;因为我也在小公司呆过&#xff0c;所以我有最直接的感受。整个部门技术人员没几个&#xff0c;我又大学刚毕业&#xff0c;带我的人&#xff0c;问啥啥不会&#xff0c;只有一个大佬&#xff0c;跳槽来的&#xff0c;是我们技术总监&#xff0c;有问题谁…...

前端面试题(基础篇七)

一、谈谈你对webpack的看法 webpack是一个模块打包工具&#xff0c;我们可以使用webpack管理我们的模块依赖&#xff0c;编译输出模块所需的静态文件。它可以很好的管理、打包web开发中所需的html、css、JavaScript以及其他各种静态文件&#xff08;使用的图片、字体图标等&am…...

ARM架构简明教程

目录 一、ARM架构 1、RISC指令集 2、ARM架构数据类型的约定 2.1 ARM-v7架构数据类型的约定 2.2 ARM-v8架构数据类型的约定 3、CPU内部寄存器 4、特殊寄存器 4.1 SP寄存器 4.2 LR寄存器 4.3 PC寄存器 二、汇编 1、汇编指令&#xff08;常用&#xff09; 2、C函数的…...

DWG转PDF字体研究记录

1.前言 最近需要对PDF中的符合业务规则的文字进行提取&#xff0c;发现有些文字不是文字信息形式存储&#xff0c;而是polyline形式表达&#xff0c;意味着仅仅有形体上的表达&#xff0c;丢失了原本的文字信息。 经过沟通得知&#xff0c;这些PDF是AutoCAD软件导出的&#xf…...

Java中如何处理日期和时间?

Java中如何处理日期和时间&#xff1f; 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Java中处理日期和时间&#xff0c;这是开发中非常常…...

Kubernetes之Pod详解

如何更好的使用好Pod&#xff1f;本文尝试从Pod组成、Namespace共享、控制器实现原理及Pod设计原则4个方面对Pod的使用进行详细阐述&#xff0c;希望对您 一、 Kubernetes Pod介绍 在 Kubernetes 中&#xff0c;Pod 是最小的可部署单元&#xff0c;包含一个或多个容器。Pod 提…...

长亭谛听教程部署和详细教程

PPT 图片先挂着 挺概念的 谛听的能力 hw的时候可能会问你用过的安全产品能力能加分挺重要 溯源反制 反制很重要感觉很厉害 取证分析 诱捕牵制 其实就是蜜罐 有模板直接爬取某些网页模板进行伪装 部署要求 挺低的 对linux内核版本有要求 需要root 还有系统配置也要修改 …...

修复漏洞Windows 2012 Server R2(CVE-2016-2183)、(CVE-2015-2808)、(CVE-2013-2566)

修复漏洞 漏洞风险等级评定标准主机风险等级评定标准漏洞概括利用注册表修复漏洞查看修复后的漏洞漏洞风险等级评定标准 危险程度危险值区域危险程度说明高7 <=漏洞风险值<= 10攻击者可以远程执行任意命令或者代码,或对系统进行远程拒绝服务攻击。中4 <=漏洞风险值&l…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...