基于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真是一个巨大的优化!

五.蝇量模式优点

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

六.蝇量的用途和优点

  • 用途:当一个类有许多实例,而这些实例能够用一致的方法控制时,用蝇量。
  • 缺点:一旦你实现了蝇量模式,那么类的单个逻辑实例,将无法拥有和其他实例不同的独立行为。也就是说牺牲了 "实例行为的独立性"。
相关推荐
Kal-Lai1 小时前
学习笔记:UR5协作机器人正运动学计算
笔记
LightYoungLee1 小时前
大模型(七)Agent AI学习笔记
人工智能·笔记·学习
2301_776508722 小时前
C++中的职责链模式实战
开发语言·c++·算法
sqyno1sky2 小时前
C++中的空对象模式
开发语言·c++·算法
星轨初途2 小时前
C++ 类和对象(下):初始化列表、static 成员与编译器优化深度剖析
android·开发语言·c++·经验分享·笔记
量子炒饭大师2 小时前
【C++ 入门】Cyber动态义体——【vector容器】vector底层原理是什么?该怎么使用他?一文带你搞定所有问题!!!
开发语言·c++·vector·dubbo
努力的lpp2 小时前
小迪安全课程第五节复习笔记:渗透测试命令与反弹连接技术
笔记·安全
学嵌入式的小杨同学2 小时前
STM32 进阶封神之路(二十三):低功耗深度解析 —— 从睡眠模式到停机模式(底层原理 + 寄存器配置)
c++·stm32·单片机·嵌入式硬件·mcu·架构·硬件架构
yunyun321232 小时前
动态库热加载技术
开发语言·c++·算法