设计模式的学习

OO:Object-Oriented

面向对象

---

《Head First设计模式》

这本书是用java写的,我是写C++的,用C++来写相关的代码

---

p2(第二页)

#ifndef DUCK_H
#define DUCK_H/*** @brief The Duck class    鸭子类*/
class Duck
{
public:Duck();/*** @brief quack 呱呱叫* 所有的鸭子都会呱呱叫* 所以在父类中实现这部分代码*/void quack();/*** @brief swim  游泳* 所有的鸭子都会游泳* 所以在父类中实现这部分代码*/void swim();/*** @brief display   展示鸭子的外观* 每种鸭子的外观特点不同,需要在子类中进行实现* 所以这里是虚函数*/virtual void display();
};#endif // DUCK_H
#ifndef MALLARDDUCK_H
#define MALLARDDUCK_H#include "duck.h"
/*** @brief The MallardDuck class 绿头鸭*/
class MallardDuck : public Duck
{
public:MallardDuck();virtual void display();
};#endif // MALLARDDUCK_H
#ifndef MALLARDDUCK_H
#define MALLARDDUCK_H#include "duck.h"
/*** @brief The MallardDuck class 绿头鸭*/
class MallardDuck : public Duck
{
public:MallardDuck();virtual void display();
};#endif // MALLARDDUCK_H

---

现在需要添加需求:一部分鸭子会飞。

如果直接在基类中添加fly(),那么意味着所有的鸭子都会飞。(所有的子类都拥有了fly() )

而橡皮鸭子是不会飞的。

---

当涉及“维护”时,为了复用目的而使用继承,并不是完美的。

---

如果子类把fly()方法覆盖掉呢?

可以,但如果再加入一种不会飞的鸭子,那么需要重新再覆盖fly()方法。

void fly()
{//覆盖,什么事都不做
}

每多一种鸭子,就需要覆盖一次fly()方法。

------

而有些鸭子不会飞,也不会叫。

---

希望找到一种建立软件的方法,让我们可以用一种对既有的代码影响最小的方式来修改软件。

这样我们就可以花较少时间重做代码,而让程序去做更酷的事。

---

继承不能很好地解决问题,因为鸭子的行为在子类中不断地改变,并且让所有的子类都有这些行为是不恰当的。

Flyable和Quackable接口一开始似乎还不错,但继承接口无法达到代码的复用。

当需要修改某个行为时,需要在定义此行为的类中修改它。

---

设计原则: 

找出应用中可能需要变化之处,把它们独立出来,不要和不需要变化的代码混在一起。

---

努力让系统中的某部分改变不会影响其他部分。

---

设计原则:

针对接口编程,而不是针对实现编程。

---

简单的多态例子:

有一个抽象类Animal,两个具体的实现:Dog和Cat继承自Animal

针对实现编程:

Dog d = new Dog();
d.bark();

针对接口编程:

Animal * animal = new Dog();
animal.makeSound();

子类实例化的动作不再需要在代码中硬编码,而是在运行时才指定具体实现的对象,

进一步封装:

a = getAnimal();
a.makeSound();

我们不关心实际的子类型是什么,我们只关心它知道如何正确地调用makeSound()。

---

#ifndef FLYBEHAVIOR_H
#define FLYBEHAVIOR_H
#include <QDebug>
/*** @brief The FlyBehavior class 飞行行为*/
class FlyBehavior
{
public:FlyBehavior(){}virtual void fly(){}
};/*** @brief The FlyWithWings class    用翅膀飞行*/
class FlyWithWings : public FlyBehavior
{
public:FlyWithWings(){}virtual void fly(){qDebug()<<"用翅膀飞行";}
};/*** @brief The FlyNoWay class    不会飞行*/
class FlyNoWay : public FlyBehavior
{
public:FlyNoWay(){}virtual void fly(){qDebug()<<"不会飞行";}
};#endif // FLYBEHAVIOR_H
#ifndef FLYBEHAVIOR_H
#define FLYBEHAVIOR_H
#include <QDebug>
/*** @brief The FlyBehavior class 飞行行为*/
class FlyBehavior
{
public:FlyBehavior(){}virtual void fly(){}
};/*** @brief The FlyWithWings class    用翅膀飞行*/
class FlyWithWings : public FlyBehavior
{
public:FlyWithWings(){}virtual void fly(){qDebug()<<"用翅膀飞行";}
};/*** @brief The FlyNoWay class    不会飞行*/
class FlyNoWay : public FlyBehavior
{
public:FlyNoWay(){}virtual void fly(){qDebug()<<"不会飞行";}
};#endif // FLYBEHAVIOR_H

关键在于:

鸭子现在会将飞行和呱呱叫的动作“委托”别人处理,而不是使用定义在Duck类或子类内的呱呱叫和飞行方法。

#ifndef DUCK_H
#define DUCK_H#include "flybehavior.h"
#include "quackbehavior.h"
/*** @brief The Duck class    鸭子类*/
class Duck
{
public:Duck();FlyBehavior * flyBehavior;QuackBehavior * quackBehavior;void performQuack(){quackBehavior->quack();}void performFly(){flyBehavior->fly();}/*** @brief display   展示鸭子的外观* 每种鸭子的外观特点不同,需要在子类中进行实现* 所以这里是虚函数*/virtual void display(){}
};#endif // DUCK_H
#ifndef MALLARDDUCK_H
#define MALLARDDUCK_H#include "duck.h"
/*** @brief The MallardDuck class 绿头鸭*/
class MallardDuck : public Duck
{
public:MallardDuck();virtual void display(){}
};#endif // MALLARDDUCK_H
#include "mallardduck.h"MallardDuck::MallardDuck()
{flyBehavior = new FlyWithWings();quackBehavior = new MuteQuack();
}
    MallardDuck mallardDuck;mallardDuck.performFly();mallardDuck.performQuack();

---

通过基类的指针析构子类时,会出现内存泄漏吗?

如果不希望内存泄漏,析构函数必须定义为虚函数。

---

设计原则:

多用组合,少用继承。

使用组合建立系统具有很大的弹性,不仅可将算法族封装成类,更可以“在运行时动态地改变行为”。

策略模式:

定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

上面的鸭子示例中:可以在运行时动态地切换鸭子相关的行为(算法)(用翅膀飞,不会飞)

------

设计是一门艺术,总是有许多可取舍的地方。

设计大师关心的是建立弹性的设计,可以维护,可以应付变化。

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

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

相关文章

九种降维算法

关于九种降维算法的一份介绍

No.8 笔记 | SQL 查询语句:数据探索的钥匙

2024/10/7 心记 - 致在路上默默奋斗的你 在当今数字化的时代&#xff0c;网络安全已成为我们生活中不可或缺的一部分。它如同守护数字世界的隐形盾牌&#xff0c;保护着我们的隐私、数据和整个社会的稳定运行。 学习网络安全&#xff0c;是踏上一段充满挑战与机遇的征程。 每一…

【Docker从入门到进阶】01.介绍 02.基础使用

1. 介绍 1.1. 什么是 Docker Docker 是一个开源的平台&#xff0c;用于开发、发布和运行应用程序。它使开发者能够以更精简的方式封装应用及其依赖&#xff0c;做到“打包一次&#xff0c;到处运行”。通过 Docker&#xff0c;您可以创建轻量级、可移植的容器&#xff0c;每个…

软件设计师(软考学习)

数据库技术 数据库基础知识 1. 数据库中的简单属性、多值属性、复合属性、派生属性简单属性&#xff1a;指不能够再分解成更小部分的属性&#xff0c;通常是数据表中的一个列。例如学生表中的“学号”、“姓名”等均为简单属性。 多值属性&#xff1a;指一个属性可以有多个值…

【网络原理】面试高频考点!!TCP协议“三次握手,四次挥手”,保姆级详解,建议收藏!

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;计算机网络那些事 通过上篇文章&#xff0c;我们可以得知TCP通过 “确认应答” 和 “超时重传”机制相辅相成&#xff0c;共同构建了 TCP的“可靠传输机制”。而为了保障建立通信和断开通信的可靠性…

PHP中的PEAR是什么

PHP中的PEAR是PHP Extension and Application Repository的缩写&#xff0c;即PHP扩展与应用库。它是一个PHP扩展及应用的代码仓库&#xff0c;提供了许多常用的PHP库和工具&#xff0c;涵盖了页面呈现、数据库访问、文件操作、数据结构、缓存操作、网络协议、WebService等许多…

忘记 MySQL 密码怎么办:破解 root 账户密码

忘记 MySQL 密码怎么办&#xff1a;破解 root 账户密码 目录 忘记 MySQL 密码怎么办&#xff1a;破解 root 账户密码1、修改 MySQL 配置文件2、不使用密码登录 MySQL3、重置 root 用户密码4、修改 MySQL 配置文件并重启 MySQL 服务5、使用新密码登录 MySQL 如果忘记密码导致无法…

解决磁盘负载不均——ElasticSearch 分片分配和路由设置

ES 分片分配&#xff08;Shard Allocation&#xff09;时间点&#xff1a; 初始恢复&#xff08;Initial Recovery&#xff09;副本分配&#xff08;Replica Allocation&#xff09;重平衡&#xff08;Rebalance&#xff09;节点添加或移除 小结&#xff1a; 准备移除节点时&a…

使用 Vue3 和 Axios 实现 CRUD 操作

文章目录 1、准备工作2、创建 Vue 3 项目3、项目结构4、实现 CRUD 操作5、运行项目6、小结在当今的前端开发中,Vue.js 作为一款流行的 JavaScript 框架,正在被越来越多的开发者所青睐。尤其是 Vue 3 引入了 Composition API 和更优雅的响应式处理,使得模板编写和状态管理变得…

CAN转WiFi模块在仓库系统中应用

CAN转WiFi模块在仓库系统中应用 我们的LCWLAN设备在实际使用中以裸板的形式放在客户的智能总线控制器中&#xff0c;客户的智能总线刀片灯&#xff0c;柔性灯货架&#xff0c;柔性感应钢网柜以及智能电子料架等设备都是接到总线控制器中&#xff0c;然后总控制器通过CAN总线和…

Qt-QSpacerItem布局相关控件(45)

目录 描述 属性 使用 控件小结 描述 使⽤布局管理器的时候,可能需要在控件之间,添加⼀段空⽩.就可以使⽤ QSpacerItem 来表⽰ 属性 width宽度height⾼度hData⽔平⽅向的 sizePolicy • QSizePolicy::Ignored : 忽略控件的尺⼨&#xff0c;不对布局产⽣影响。 • QSizePol…

免费高可用软件

高可用软件是指那些能够提供高可用性、高可靠性的软件&#xff0c;它们在各种应用场景下都能确保系统的稳定运行。以下是四款免费的高可用软件&#xff0c;它们在不同领域都表现出色&#xff0c;能够满足各种高可用性需求。 一、PanguHA PanguHA是一款专为Windows平台设计的双…

贪心算法c++

贪心算法C概述 一、贪心算法的基本概念 贪心算法&#xff08;Greedy Algorithm&#xff09;&#xff0c;又名贪婪法&#xff0c;是一种解决优化问题的常用算法。其基本思想是在问题的每个决策阶段&#xff0c;都选择当前看起来最优的选择&#xff0c;即贪心地做出局部最优的决…

网络通信——OSPF协议(基础篇)

这里基础是因为没有讲解OSPF中的具体算法过程&#xff0c;以及其中很多小细节。后续会更新。 目录 一.OSPF的基础信息 二.认识OSPF中的Router ID 三.OSPF中的三张表 四.OSPF中的度量方法&#xff08;计算开销值&#xff09; 五. OSPF选举DR和BDR&#xff08;就是这个区域…

音视频入门基础:FLV专题(9)——Script Tag简介

一、SCRIPTDATA 根据《video_file_format_spec_v10_1.pdf》第75页到76页&#xff0c;如果某个Tag的Tag header中的TagType值为18&#xff0c;表示该Tag为Script Tag&#xff08;脚本Tag&#xff0c;又称Data Tag、SCRIPTDATA tag&#xff09;。这时如果Filter的值不为1表示未加…

【Android】Jetpack组件之LifeCycle

引言 Lifecycle组件是Android Jetpack架构组件之一&#xff0c;它提供了一种方法来管理Android组件&#xff08;如Activity、Fragment和服务&#xff09;的生命周期。Lifecycle组件帮助你执行与生命周期相关联的操作&#xff0c;确保在适当的时间发生适当的事情&#xff0c;例…

深度学习项目----用LSTM模型预测股价(包含LSTM网络简介,代码数据均可下载)

前言 前几天在看论文&#xff0c;打算复现&#xff0c;论文用到了LSTM&#xff0c;故这一篇文章是小编学LSTM模型的学习笔记&#xff1b;LSTM感觉很复杂&#xff0c;但是结合代码构建神经网络&#xff0c;又感觉还行&#xff1b;本次学习的案例数据来源于GitHub&#xff0c;在…

越差越好?为什么简单反而赢了,这背后究竟有什么秘诀?

你有没有发现,软件界里那些最成功的产品,往往并不是最复杂、最强大的?我们用的很多东西,看起来功能普通,甚至有些粗糙,但就是这样简陋的设计,反而成了市场上的赢家。 也许你玩过Flappy Bird这个游戏:它的设计非常简单,玩家只需要点击屏幕让小鸟飞行,避开管道障碍。游…

【微服务】springboot 实现动态修改接口返回值

目录 一、前言 二、动态修改接口返回结果实现方案总结 2.1 使用反射动态修改返回结果参数 2.1.1 认识反射 2.1.2 反射的作用 2.1.3 反射相关的类 2.1.4 反射实现接口参数动态修改实现思路 2.2 使用@ControllerAdvice 注解动态修改返回结果参数 2.2.1 注解作用 2.2.2 实…

Llama 3.2 智能代理开发教程

构建研究代理可能很复杂&#xff0c;但使用 LangChain 和 Ollama&#xff0c;它会变得更加简单和模块化。 在本教程中&#xff0c;我们将向你展示如何基于Llama 3.2创建一个研究代理&#xff0c;该代理可以路由查询、执行网络搜索并使用工作流和 LLM 的组合生成详细响应。最后…