Head First设计模式——策略模式

2023-10-27

 

 

Head First设计模式》是一本介绍设计模式的书籍,书中的设计模式主要是用Java语言进行实现,由于本人对C++比较熟悉,因此在阅读这本书籍时,尽自己所能,用C++重新去实现书中所涉及到的设计模式。若有错误或需要进一步讨论之处,望阅览者不吝赐教!

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

需求:一家公司需要设计一款模拟鸭子游戏的电子软件。游戏中会出现各种鸭子,比如橡皮鸭、诱饵鸭、鸭等,这些鸭子会有不同的行为,比如有的会叫、有的不会叫、有的会飞、有的不会飞等。为了适应不同的鸭子对象和鸭子行为,可以用策略模式进行整个框架的构建。

1、设计一个鸭子类Duck,一个飞行行为接口类(C++里面没有接口的的说法,这里套用Java里的说法,更容易理解)FlyBehavior,一个叫声接口类QuackBehavior,这是第一个设计模式,所以没有考虑周全,将这三个类放到了一个.h文件里;一般而言,应该分开为三个.h文件。Duck.h、Duck.cpp文件具体代码如下:

#pragma once
#include<iostream>
using namespace std;

class FlyBehavior;
class QuackBehavior;

class CDuck
{
public:
	CDuck();
	~CDuck();

	virtual void display() {}
	virtual void performFly();
	virtual void performQuack();

	void setFlyBehavior(FlyBehavior *fb);
	void setQuackBehavior(QuackBehavior *qb);
	void swim();

protected:
	FlyBehavior* flyBehavior;
	QuackBehavior* quackBehavior;
};

class FlyBehavior
{
public:
	FlyBehavior() {}
	~FlyBehavior() {}

	virtual void fly() {}
private:

};

class QuackBehavior
{
public:
	QuackBehavior() {}
	~QuackBehavior() {}

	virtual void quack(){}
private:

};

class FlyWithWings:public FlyBehavior      //第一个具体飞行行为类
{
public:
	FlyWithWings() {}
	~FlyWithWings() {}
	void fly()
	{
		cout << "I'm flying!!" << endl;
	}
private:

};

class FlyNoWay :public FlyBehavior   //第二个具体飞行行为类
{
public:
	FlyNoWay() {}
	~FlyNoWay() {}
	void fly()
	{
		cout << "I can't fly!!" << endl;
	}
private:

};

class FlyRocketPowered:public FlyBehavior  //第三个具体飞行行为类
{
public:
	FlyRocketPowered(){}
	~FlyRocketPowered(){}

	void fly()
	{
		cout << "I'm flying with rocket!!" << endl;
	}

private:

};

class Quack:public QuackBehavior      //第一个具体叫声类
{
public:
	Quack() {}
	~Quack() {}

	void quack()
	{
		cout << "Quack" << endl;
	}
private:

};

class MuteQuack :public QuackBehavior  //第二个具体叫声类
{
public:
	MuteQuack() {}
	~MuteQuack() {}

	void quack()
	{
		cout << "<< Silence >>" << endl;
	}
private:

};

class Squeak :public QuackBehavior  //第三个具体叫声类
{
public:
	Squeak() {}
	~Squeak() {}

	void quack()
	{
		cout << "Squeak" << endl;
	}
private:

};



#include "Duck.h"

CDuck::CDuck()
{
}

CDuck::~CDuck()
{
}

void CDuck::performFly()
{
	flyBehavior->fly();
}

void CDuck::performQuack()
{
	quackBehavior->quack();
}

void CDuck::swim()
{
	cout << "All ducks float,even decoys!!" << endl;
}

void CDuck::setFlyBehavior(FlyBehavior* fb)
{
	flyBehavior = fb;
}

void CDuck::setQuackBehavior(QuackBehavior *qb)
{
	quackBehavior = qb;
}

2、创建两个具体鸭子类:MallardDuck、ModelDuck,MallardDuck.h、MallardDuck.cpp、ModelDuck.h、ModelDuck.cpp文件具体代码如下:

#pragma once
#include "Duck.h"
class CMallardDuck :public CDuck
{
public:
	CMallardDuck();
	~CMallardDuck();

	void display();
};
#include "MallardDuck.h"

CMallardDuck::CMallardDuck()
{
	quackBehavior = new Quack();
	flyBehavior = new FlyWithWings();
}

CMallardDuck::~CMallardDuck()
{

}

void CMallardDuck::display()
{
	cout << "I'm a real Mallard duck!!" << endl;
}
#pragma once
#include "Duck.h"
class CModelDuck :
	public CDuck
{
public:
	CModelDuck();
	~CModelDuck();
	void display();
};

#include "ModelDuck.h"



CModelDuck::CModelDuck()
{
	flyBehavior = new FlyNoWay();
	quackBehavior = new Quack();
}


CModelDuck::~CModelDuck()
{
}

void CModelDuck::display()
{
	cout << "I'm a model duck!!" << endl;
}

3、测试代码和结果如下:

/*
策略模式:定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让
算法的变化独立于使用算法的客户
*/
#include "Duck.h"
#include "MallardDuck.h"
#include "ModelDuck.h"

int main()
{
	CDuck* mallard = new CMallardDuck();
	mallard->performFly();
	mallard->performQuack();

	CDuck* model = new CModelDuck();
	model->performFly();
	model->setFlyBehavior(new FlyRocketPowered());
	model->performFly();

	delete mallard;
	delete model;
	return 0;
}

在讲述策略模式时,书中涉及到了三个OO原则:

1、封装变化,即将框架中易于变化的部分抽象出来,形成独立的类;

2、多用组合,少用继承,即类与类之间尽量处于合作关系,而不是依赖关系;

3、针对接口编程,不针对具体实现编程,即对接口编程,当需要进行变动时,只需变动接口即可。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Head First设计模式——策略模式 的相关文章

  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 对类 static constexpr 结构的未定义引用,g++ 与 clang

    这是我的代码 a cp p struct int2 int x y struct Foo static constexpr int bar1 1 static constexpr int2 bar2 1 2 int foo1 return
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 为什么这个字符串用AesCryptoServiceProvider第二次解密时不相等?

    我在 C VS2012 NET 4 5 中的文本加密和解密方面遇到问题 具体来说 当我加密并随后解密字符串时 输出与输入不同 然而 奇怪的是 如果我复制加密的输出并将其硬编码为字符串文字 解密就会起作用 以下代码示例说明了该问题 我究竟做错
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置

随机推荐

  • printf(“%d,%d\n“,i--,i++)

    sample cpp include
  • Windows 下创建定时任务执行Python脚本

    文章目录 一 环境 二 脚本 三 创建定时任务 1 打开 任务计划程序 2 打开 创建任务 窗口 3 创建任务一一常规 4 创建任务一一触发器 5 创建任务一一操作 6 创建任务一一条件 7 创建任务一一设置 8 完成任务创建 四 验证定时
  • 记录自己在结构光三维重建领域的学习过程(一)

    仿真数据集与真是数据集之间差异较大 二者的网络均不可完美预测另一种数据 寻找解决办法 首先确定是不是数据的问题 阅读论文 Light field structured light projection data generation wit
  • 关于存储过程中SQL语句IN条件传参注意说

    背景说明 在数据库操作中我们经常会用到查询语句 在一些情况下 需要使用到IN条件 正常的查询中IN需要注意的是最好in中的参数不能超过1000个 超过1000的时候oracle会抛出异常 这个如何处理先不提 这次要说的是 如果在存储过程中使
  • 某单位分配到一个地址块 136.23.12.64/26。现在需要进一步划分为4个一样大的子网。试问:

    1 每个子网的网络前缀有多长 2 每个子网中有多少个地址 3 每个子网的地址块是什么 4 每一个子网可分配给主机使用的最小地址和最大地址是什么 姐
  • JS中的邮箱验证

    通过js在前端对用户输入进行校验 即可以产生较好的交互体验 也可以减轻后台的压力 邮箱的基本格式要求 1 只能以单词字符开头 即a z A Z 0 9 2 只能有一个 3 后面有一个到多个点 并且点不能在最后 4 特殊字符不能开头和结尾 使
  • 数据存储,详细讲解

    数据存储 详细讲解 数据类型的介绍 整形的内存存储 大小端介绍 浮点数的存储 数据类型的介绍 1 内置类型 char 字符数据类型 1 short 短整型 2 int 整形 4 long 长整型 4 8 long long 更长的整形 8
  • matlab之数组反序输出

    a 1 2 3 4 5 a end 1 1 5 4 3 2 1 转载于 https www cnblogs com yibeimingyue p 11201805 html
  • 高阶数据结构之并查集

    文章目录 并查集 并查集的常规实现 并查集的简化实现 算法题 模板 朴素的并查集 维护size的并查集 维护到祖宗节点的并查集 并查集 在某些应用问题中 需要将n个不同的元素划分成一些不想交的集合 开始时 每个元素自成一个单元集合 然后按照
  • 一文搞懂状态模式

    原理 状态机有三个组成部分 状态 事件 动作 遇到不同的事件会触发状态的转移和动作的执行 不过动作不是必须的 可能只有状态的转移 没有动作的执行 状态模式的目的就是实现状态机 案例带入 比如 超级马里奥 在游戏中 马里奥可以变身为多种形态
  • 抖音究竟对线下生意有没有价值?

    戳上方增长黑盒Growthbox点亮星标 深度研究不错过 主笔 邹小困 研究员 彬超 Emma 出品 增长黑盒研究组 01 防火防盗防抖音 互联网世界的后起之秀字节跳动 如同进击的巨人 在短短几年内就已将业务的触角伸向各个领域 图为chat
  • Java基础(IO输入输出流,读写文件操作,对象序列化)

    IO 输入输出流基本概念 输入流 信息从程序空间之外的地方流入程序空间里面 输出流 信息从程序空间里面流到程序空间之外的地方 输入输出流的分类 从流的方法划分 输入流 输入流 从流的分工划分 节点流 访问文件进行输入输出操作的流 处理流 在
  • IDEA常见错误:程序包org.apache.commons.xxx不存在

    具体错误 Could not transfer artifact org apache commons commons text pom 1 1 from to Nexus Repository Nexus Repository Manag
  • 全新【Photoshop 2022 for mac】中文版发布下载 支持M1 M1X M2处理器 详细安装教程

    Adobe PhotoShop 2022 for mac 23 0 是 Adobe 2022 中最重要的组成软件之一 PhotoShop主要用来处理图像 是行业内最流行的图像处理软件 ps 2022 更加智能化和强大 Adobe Photo
  • CAN db++(创建DBC文件)学习笔记

    CAN db 学习笔记 1 新建文件 2 模块介绍 3 建立DBC的过程 自下而上 信号 报文 节点 1 信号 2 报文 3 建立报文与信号的关系 4 建立信号在报文里的位置 因为前面定义了报文的数据长度 且把信号放到了报文里面 那么信号在
  • 【Linux_CentOS7】 systemctl restart named报错-Job for named.service failed because the control process

    14天阅读挑战赛 努力是为了不平庸 算法学习有些时候是枯燥的 这一次 让我们先人一步 趣学算法 欢迎记录下你的那些努力时刻 算法学习知识点 算法题解 遇到的算法bug 等等 在分享的同时加深对于算法的理解 同时吸收他人的奇思妙想 一起见证技
  • Taro+vue3小程序开启分享他人和分享到朋友圈

    import Taro useShareAppMessage useShareTimeline from tarojs taro onMounted gt Taro showShareMenu withShareTicket true me
  • 有趣的java代码_求一些有趣的java小程序?

    不请自来 用eclipse写的一个输出爱心的小程序 应该算是比较有趣的吧 下面是程序内容 public class love public static void main String args TODO Auto generated m
  • BeanUtils.copyProperties的用法(超详细,建议收藏)

    常见场景 我们如果有两个具有很多相同属性名的JavaBean对象a和b 想把a中的属性赋值到b 例如 接口中将接收到的前端请求参数XxxReqVo 我们想把这个入参转化为XxxQuery对象作为数据库的查询条件对象 传统做法是手动set 即
  • Head First设计模式——策略模式

    Head First设计模式 是一本介绍设计模式的书籍 书中的设计模式主要是用Java语言进行实现 由于本人对C 比较熟悉 因此在阅读这本书籍时 尽自己所能 用C 重新去实现书中所涉及到的设计模式 若有错误或需要进一步讨论之处 望阅览者不吝