基于C++的《Head First设计模式》笔记——蝇量模式

目录

一.专栏简介

二.蝇量模式概念

三.不使用蝇量模式的反例

四.蝇量模式优化

五.蝇量模式优点

六.蝇量的用途和优点


一.专栏简介

本专栏是我学习《head first》设计模式的笔记。这本书中是用Java语言为基础的,我将用C++语言重写一遍,并且详细讲述其中的设计模式,涉及是什么,为什么,怎么做,自己的心得等等。希望阅读者在读完我的这个专题后,也能在开发中灵活且正确的使用,或者在面对面试官时,能够自信地说自己熟悉常用设计模式。

本章将开始**蝇量模式(Flyweight Pattern)**的学习。

二.蝇量模式概念

当某个类的一个实例可以用于提供许多虚拟实例时,使用蝇量模式。

下面我们举一个反例,然后用蝇量模式改进。

三.不使用蝇量模式的反例

假设我们要在一个田园游戏中放置非常多的树,那么我们容易想到直接实例化一堆树,然后根据树的位置和年龄(推断大小)绘制在界面上。这里我们就不实际绘制了,用标准输出代替。代码如下:

Flyweight.h:

cpp 复制代码
#pragma once
#include <iostream>
using namespace std;

class Tree
{
public:
	Tree(int x, int y, size_t age):
		_x(x), _y(y), _age(age)
	{}
	// 强制访问每个 Tree 对象的成员,让操作系统把虚拟内存映射到物理内存,从而产生实际的内存开销,便于观察
	void display()
	{
		cout << "树显示在(" << _x << "," << _y << ")处,年龄为:" << _age << "岁!" << endl;
	}
private:
	int _x;
	int _y;
	size_t _age;
};

main.cpp:

cpp 复制代码
#include "Flyweight.h"
#include <vector>
#include <windows.h>

const int TREECOUNT = 100000000;

int main()
{
	vector<Tree*> trees;
	for (int i = 0;i < TREECOUNT;++i)
	{
		Tree* tree = new Tree(i, i + 1, i + 2);
		trees.push_back(tree);
	}

	for (const auto& e : trees)
		e->display();

	Sleep(60000);

	return 0;
}

代码很简单,就是一个Tree类,我们new很多很多个Tree,然后调用它们的display()函数进行打印输出。这里调用display()函数的操作非常关键,因为访问成员变量会造成缺页中断,操作系统将虚拟内存映射到物理内存,从而造成实际的内存开销,便于我们观察。

运行之前我电脑的内存占用:

仅百分之48。

运行之后:

内存占用高达百分之95,内存差点爆掉。

四.蝇量模式优化

直接上代码,代码如下:

FlyWeight.h:

cpp 复制代码
#pragma once
#include <iostream>
#include <vector>
using namespace std;

class TreeManager
{
public:
	void addTree(int x, int y, size_t age)
	{
		treePositions.push_back(make_pair(x, y));
		ages.push_back(age);
	}
	void displayTrees()
	{
		for (int i = 0;i < treePositions.size(); ++i)
		{
			Tree::display(treePositions[i].first, treePositions[i].second, ages[i]);
		}
	}
private:
	vector<pair<int, int>> treePositions;		// 所有树的位置
	vector<size_t> ages;						// 所有树的年龄
};

main.cpp:

cpp 复制代码
#include "Flyweight.h"
#include <windows.h>

const int TREECOUNT = 100000000;

int main()
{
	TreeManager treeManager;
	for (int i = 0;i < TREECOUNT;++i)
	{
		treeManager.addTree(i, i + 1, i + 2);
	}

	treeManager.displayTrees();

	Sleep(60000);

	return 0;
}

这里我用一个TreeManager存储了所有树的状态,然后Tree类里的display()函数直接变成静态的,最终在main()函数里一个Tree对象都没有实例化,只是使用treeManager这一个对象,这个对象在displayTrees()中读取所有树的属性,调用静态的Tree::display()函数进行显示(实际上是打印)。

运行结果:

同样是显示一亿棵树,这里我的内存占用骤降至百分之58,对比之前的百分之95真是一个巨大的优化!

五.蝇量模式优点

  • 减少运行时对象实例的数目,节省内存。
  • 把许多"虚拟"对象的状态集中放进一个地方。

六.蝇量的用途和优点

  • 用途:当一个类有许多实例,而这些实例能够用一致的方法控制时,用蝇量。
  • 缺点:一旦你实现了蝇量模式,那么类的单个逻辑实例,将无法拥有和其他实例不同的独立行为。也就是说牺牲了 "实例行为的独立性"。
相关推荐
用户6242931966220 分钟前
告别 Electron 臃肿与 Wireshark 老化界面:用 Rust + Tauri 2.0 构建多总线网络与现场总线深度分析仪 Omni-Probe
设计模式
是2的10次方啊2 小时前
设计模式与生活㉒:暖气热不热,得一间一间摸过去
设计模式
Star(up up up)2 小时前
Redis Windows 安装教程:使用Windows 的 Redis 压缩包
redis·笔记·学习·程序人生·云原生·学习方法·改行学it
ShineWinsu2 小时前
对于Qt:QTreeWidget常见属性以及QTreeWidgetItem类的解析
开发语言·c++·qt·gui·客户端·多叉树·qtreewidget
希和20272 小时前
江科大 51 单片机课程笔记:DS1302 实时时钟 + LCD1602 可调电子钟(小白逐行讲解)
笔记·单片机·嵌入式硬件
落羽的落羽3 小时前
【C++】C++17的主要特性
linux·服务器·开发语言·c++·算法·机器学习
岑梓铭3 小时前
《考研408数据结构》第七章(B树 和 B+树)复习笔记
数据结构·笔记·b树·考研·408
bigbread7 小时前
迭代器模式-在区域健康档案导出中的实战应用
设计模式
Go Work8 小时前
docker 占满根分区时先分清谁在吃盘
经验分享·笔记
汉克老师8 小时前
《从C++小白到算法高手:GESP 1—8级成长地图》第一讲:认识GESP——从编程新手到算法探索者
c++·gesp·信息学竞赛·小学生学c++