c++ 设计模式 的课本范例(中)

(10)单例模式 singleton 。整个应用程序执行时,只有一个单例模式的对象。

class GameConfig    // 懒汉式,啥时候用单例对象,啥时候创建。
{
private:
	static GameConfig* ptrGameConfig;  // 这些函数都作为私有函数,不让外界调用
	GameConfig() {}
	~GameConfig() {}
	GameConfig(const GameConfig&) {}
	GameConfig& operator= (const GameConfig&) {}
public:
	static GameConfig* getGameConfig() 
	{
		if (ptrGameConfig)  // 本代码非线程安全,需要在  main 主线程中,在创建子线程之前,创建单例模式的对象
			ptrGameConfig = new GameConfig();

		return ptrGameConfig;
	}
};
GameConfig* GameConfig::ptrGameConfig = nullptr;

int main()
{
	auto ptr = GameConfig::getGameConfig();

	return 0;
}

下面介绍饿汉式的单例对象生成:

class GameConfig   // 饿汉式,在程序启动时候,在 main 函数执行前,就完成对 单例对象的初始化与创建
{
private:
	static GameConfig* ptrGameConfig;  // 这些函数都作为私有函数,不让外界调用
	GameConfig() {}
	~GameConfig() {}
	GameConfig(const GameConfig&) {}
	GameConfig& operator= (const GameConfig&) {}
public:
	static GameConfig* getGameConfig() { return ptrGameConfig;	}
};
GameConfig* GameConfig::ptrGameConfig = new GameConfig();  // 此时可以调用私有的单例模式的构造函数

int main()
{
	auto ptr = GameConfig::getGameConfig();

	return 0;
}

若有其它静态全局变量的初始化引用了单例对象的数据,可能会导致错误。因为各个 cpp 文件的全局静态变量的初始化的顺序是不太确定的。

以上的单例模式返回的都是单例对象的指针。可以改为返回单例对象的引用,用引用比指针更符合 c++ 的风格,且可以少起变量名:

class GameConfig  
{
private:
	GameConfig() {}    // 这些函数都作为私有函数,不让外界调用
	~GameConfig() { }
	GameConfig(const GameConfig&) {}
	GameConfig& operator= (const GameConfig&) {}
public:
	static GameConfig& getGameConfig() 
	{ 
		static GameConfig gameConfig;
		return gameConfig;
	}
};


int main()
{
	auto& gameConfig = GameConfig::getGameConfig();   // 直接使用 auto 是值复制, auto & 才是创建引用。

	return 0;
}

用 MFC 框架测试不显式析构单例模式的对象,是否会造成内存泄露。发现不会。因为 这些 static 静态对象是在 main 函数之前就构建出来的,静态对象的析构与回收由 main 函数结束后由系统回收。也就不存在内存泄露。 MFC 框架测试的内存泄露应该指的是在 main 函数结束前,申请的内存没有显式释放,才叫内存泄露,贴图如下,无论使用的是静态单例模式对象的指针还是引用,都没提示内存泄露:

在这里插入图片描述

(11)外观模式 fasade 。用于隔离类与类,代码与代码之间的强耦合。比如设置游戏环境:图形、声音、特效。设置会很繁琐,细致。这就是代码里的强耦合。可以在游戏界面里提供两个按钮:高配模式与低配模式。由这两个模式自行进行所有的游戏环境设置。这高配低配按钮的实现,就是外观模式。词典翻译是 fasade 正面;(尤指虚假的)外表,表面,外观。个人感觉表面模式更合适。表面,区别于内核,由表面联接与内核打交道。

class Graphic
{
private:
	Graphic() {}
	~Graphic() {}
	Graphic(const Graphic&) {}
	Graphic& operator=(const Graphic&) {}
public:
	static Graphic&  getGraphic()
	{
		static Graphic gra;
		return gra;
	}

	void effects_mode(bool b)  // 是否开启特效
	{
		if (b) cout << "开启高特效\n\n";
		else   cout << "不开启高特效\n\n";
	}

	void resolution(int i , int j)	{	cout << "分辨率 :" << i << " * " << j << "\n\n";	}
};

class Sound
{
private:
	Sound() {}
	~Sound() {}
	Sound(const Sound&) {}
	Sound& operator=(const Sound&) {}
public:
	static Sound&  getSound()
	{
		static Sound sound;
		return sound;
	}

	void bgSound(bool b)     // 是否开启背景音
	{
		if (b) cout << "开启背景音\n\n";
		else   cout << "不开启背景音\n\n";
	}

	void envirSound(bool b)  // 是否开启环境音效
	{
		if (b) cout << "开启环境音效\n\n";
		else   cout << "不开启环境音效\n\n";
	}
};

class Facade // 外观类,用于隔离类之间的强耦合
{
private:
	Facade() {}
	~Facade() {}
	Facade(const Facade&) {}
	Facade& operator=(const Facade&) {}
public:
	static Facade& getFacade()
	{
		static Facade facade;
		return facade;
	}

	void config(bool high)
	{
		auto& graphic = Graphic::getGraphic();
		auto& sound = Sound::getSound();

		if (high)
		{
			graphic.effects_mode(true);
			graphic.resolution(1920 , 1080);

			sound.bgSound(true);
			sound.envirSound(true);
		}
		else
		{
			graphic.effects_mode(false);
			graphic.resolution(1366, 800);

			sound.bgSound(false);
			sound.envirSound(false);
		}
	}

};

int main()
{
	auto& fasade = Facade::getFacade();
	fasade.config(true);
	cout << "----------------------\n\n";
	fasade.config(false);
	return 0;
}

测试结果如下:

在这里插入图片描述

(12)命令模式 Command 。例如 wps 软件的菜单,由一个个命令组成。把这些执行了的命令,集合到容器里,如 list 双向链表。就可以编写日志,或者支持了撤销操作, undo 。

class Cook
{
public:
	void fish() { cout << "厨师做了鱼\n\n"; }
	void beef() { cout << "厨师做了牛肉\n\n"; }
};

class Command    // 封装命令
{
protected: Cook* pCook;
public:
	Command( Cook* p) :pCook(p) {}
	virtual ~Command() {}
	virtual void excute() = 0;
};

class Command_Fish : public Command  // 做鱼命令
{
public:
	Command_Fish( Cook* p) : Command(p) {}
	void excute() override { this->pCook->fish(); }
};

class Command_Beef : public Command   // 做牛肉命令
{
public:
	Command_Beef(Cook* p) : Command(p) {}
	void excute() override { this->pCook->beef(); }
};

class Waiter              // 用服务员角色一次可以执行很多命令
{
private: list<Command*> listCommand;
public:
	void addCommand(Command* p)    { listCommand.push_back(p); }
	void deleteCommand(Command* p) { listCommand.remove(p); }
	
	void excute() 
	{
		for (auto iter = listCommand.begin(); iter != listCommand.end(); iter++)
			(*iter)->excute();
	}
};

int main()
{
	Cook cook;
	Command_Fish cmdFish(&cook);
	Command_Beef cmdBeef(&cook);

	Waiter waiter;
	waiter.addCommand(&cmdFish);
	waiter.addCommand(&cmdBeef);

	waiter.excute();

	return 0;
}

测试结果如下:

在这里插入图片描述

(13)迭代器模式 itertor 。主要适用于对容器的操作,定义了迭代器模式,以对容器进行增删改查的操作,同时要良好的组织这些数据结构,以实现高效。目前迭代器模式用的不多了,因为 STL 标准库定义了各种容器及其迭代器。库大师们的顶尖的容器设计,我们直接用就可以了。

for ( auto iter = vector . begin() ; iter != vector . end() ; iter++ )
	auto temp = * iter ;

以上代码显示了定义一个迭代器时应具有的最小功能: begin() 函数返回容器的头部, end() 函数返回容器的尾部 , 迭代器要支持 自加
的运算, * 运算符返回迭代器指向的容器中的元素。从而由这些函数配合完成对容器的遍历操作。即使以后要咱们自己写迭代器,也应该模仿库大师们的代码比如用模板方式定义容器及其迭代器。

(14) 组合模式 compasite 。 对于文件系统,一个目录可以包含文件与目录,子目录里又可以包含新的文件与目录。为了描述和组织这种树型的数据结构,编码的方式叫做组合模式,其实更确切的叫法应该叫树型模式。

先给出第一版代码与测试结果:

class File
{
private:
	string fileName;
public:
	File(const string& s) : fileName(s) {}

	void showName(const string& indentStr) { cout << indentStr << "-" << fileName << '\n'; }  // indent : 缩进
};

class Directory
{
private:
	string dirName;
	list<File*> listFile;
	list<Directory*> listDirectory;
public:
	Directory(const string& s) : dirName(s) {}

	void addFile(File* f) { listFile.push_back(f); }
	void addDir(Directory* d) { listDirectory.push_back(d); }

	void showName(const string& indentStr)
	{
		cout << indentStr << '+' << dirName << '\n';
	
		string newIndentStr = indentStr + "    ";

		for (auto iter = listFile.begin(); iter != listFile.end(); iter++)
			(*iter)->showName(newIndentStr);

		for (auto iter = listDirectory.begin(); iter != listDirectory.end(); iter++)
			(*iter)->showName(newIndentStr);

	}
};

int main()
{
	File h("h"), i("i") , e("e") , f("f") , b("b") , c("c");
	Directory g("G") , d("D") , a("A");

	g.addFile(&h);
	g.addFile(&i);

	d.addFile(&e);
	d.addFile(&f);

	a.addFile(&b);
	a.addFile(&c);
	a.addDir(&d);
	a.addDir(&g);

	a.showName("");

	return 0;
}

测试结果如下,即为图中的目录进行了编码:

在这里插入图片描述

以上版本把 文件和目录作为了两种类型。其实可以把其视为一种类型,用类的继承与多态来实现,由此得到组合模式的第二版(例子同上):

class FileSystem // 把文件类型与目录类型视为同一种类型
{
public:
	virtual ~FileSystem() {}
	virtual void showName(int indentNum) = 0;
	virtual int addFile(FileSystem* f) = 0;  // 返回值 0 表示正确给目录增删了文件, 返回 -1 表不应当对文件类型进行目录的增删操作
	virtual int addDir(FileSystem* d) = 0;
};

class File : public FileSystem
{
private:
	string fileName;
public:
	File(const string& s) : fileName(s) {}

	virtual int addFile(FileSystem* f) { return -1; }
	virtual int addDir(FileSystem* d) { return -1; }

	void showName(int indentNum)   // indent : 缩进
	{
		for (int i = 0; i < indentNum; i++)
			cout << "    ";

		cout << "-" << fileName << '\n';
	}
};

class Directory : public FileSystem
{
private:
	string dirName;
	list<FileSystem*> listFS;
public:
	Directory(const string& s) : dirName(s) {}

	int addFile(FileSystem* f) { listFS.push_back(f); return 0; }
	int addDir(FileSystem* d) { listFS.push_back(d); return 0; }

	void showName(int indentNum) override
	{
		for (int i = 0; i < indentNum; i++)
			cout << "    ";
	
		cout << "+" << dirName << '\n';

		indentNum++;

		for (auto iter = listFS.begin(); iter != listFS.end(); iter++)
			(*iter)->showName(indentNum);
	}
};

int main()
{
	File h("h"), i("i") , e("e") , f("f") , b("b") , c("c");
	Directory g("G") , d("D") , a("A");

	g.addFile(&h);
	g.addFile(&i);

	d.addFile(&e);
	d.addFile(&f);

	a.addFile(&b);
	a.addFile(&c);
	a.addDir(&d);
	a.addDir(&g);

	a.showName(0);

	return 0;
}

(15) 状态模式 state。用以解决以下场景:在编译原理中,根据一门语言的语法,编写出有限状态机。对代码的编译过程,实际始终是在该有限状态机的几个状态上跳转。这几个状态,足以满足用该门语法编写的所有代码情形。或者游戏里,打怪物。怪物受伤后的状态,始终就那几种,有章可循。给出课本代码,写在一个页面了,为了简洁,突出整体。没有拆分成头文件与 cpp 文件。

class Monster;

class Status   // 状态的基类
{
public:
	virtual ~Status() {}
	virtual void attacked(int power, Monster* ptrMonstor) = 0;
};

class Status_Violent : public Status  // 出于编译原理的从上往下编译,只能把包含大量符号的函数体下移。否则总提示符号找不到
{
public:
	virtual void attacked(int power, Monster* ptrMonstor);

	static Status* getStatusObj();
};

class Monster
{
private:
	int life;
	Status* pStatus;  // 这里原先使用了左值引用,但不好使,总因为 是否具有 const 属性报错,改成课本上的指针了。
public:
	Monster() : life(500), pStatus(Status_Violent::getStatusObj()) {}  // 新生怪物处于  violent 状态,满血
	int getLife() { return life; }
	void setLife(int t) { life = t; }
	Status* getStatus() { return pStatus; }
	void setStatus(Status* s) { pStatus = s; }
	void attacked(int power) { pStatus->attacked(power, this); }
};


class Status_Dead : public Status
{
public:
	virtual void attacked(int power, Monster* ptrMonstor) {	}

	static Status* getStatusObj()
	{
		static Status_Dead objDead;
		return &objDead;
	}
};

class Status_Fear : public Status
{
public:
	virtual void attacked(int power, Monster* ptrMonstor)
	{
		cout << " 怪物处于 Fear 状态 , " << " 但受到了 " << power << "  点攻击  , ";

		int newLife = ptrMonstor->getLife() - power;

		if (newLife >= 1)
			cout << "  仍处于 fear 状态\n\n";
		else
		{
			cout << "  进入了 Dead 状态\n\n";
			ptrMonstor->setStatus(Status_Dead::getStatusObj());
		}

		ptrMonstor->setLife(newLife);
	}

	static Status* getStatusObj()
	{
		static Status_Fear objFear;
		return &objFear;
	}
};

void Status_Violent::attacked(int power, Monster* ptrMonstor)  // 这个函数包含的符号最多,只能放在最后,要不总提示符号找不到
{
	cout << " 怪物处于 violent 状态 , " << " 但受到了 " << power << "  点攻击  , ";

	int newLife = ptrMonstor->getLife() - power;

	if (newLife >= 300)
		cout << "  仍处于 violent 状态\n\n";
	else if (newLife >= 1)
	{
		cout << "  进入了 fear 状态\n\n";
		ptrMonstor->setStatus(Status_Fear::getStatusObj());
	}
	else
	{
		cout << "  进入了 Dead 状态\n\n";
		ptrMonstor->setStatus(Status_Dead::getStatusObj());
	}

	ptrMonstor->setLife(newLife);
}

Status*  Status_Violent:: getStatusObj()
{
	static Status_Violent objViolent;
	return &objViolent;
}

int main()
{
	Monster m;
	m.attacked(100);
	m.attacked(150);
	m.attacked(50);
	m.attacked(400);
	return 0;
}

测试结果如下:

在这里插入图片描述

(16)享元模式 Flyweight 。也叫蝇量模式。比如围棋游戏,要绘制棋子。只要知道棋子的颜色和坐标信息,就可以绘制出该棋子。但也会造成创建大量的重复的小对象–棋子。由此提出享元模式。让程序中代码共享共用一些对象,达到减少内存使用提高效率的效果。比如可以只在围棋环境中创建黑子白子两个对象。依据位置,重复在不同坐标处绘制。以下给出范例代码:

enum Color{ black , white };

struct Position
{
	int x;
	int y;
};

class Piece
{
public:
	virtual ~Piece() {}
	virtual void draw( const Position& p) = 0;
};

class Piece_White : public Piece
{
public:
	void draw(const Position& p) override
	{
		cout << "  在棋盘 ( " << p.x << " , " << p.y << " ) 处,画了一个白棋子\n\n";
	}
};

class Piece_Black : public Piece
{
public:
	void draw(const Position& p) override
	{
		cout << "  在棋盘 ( " << p.x << " , " << p.y << " ) 处,画了一个黑棋子\n\n";
	}
};

class Factory
{
private:
	map< Color, Piece* > mapPiece;
public:
	~Factory()
	{
		for (auto iter = mapPiece.begin(); iter != mapPiece.end(); iter++)
			//delete iter->second;  这两种写法是等价的
			delete (*iter).second;
	}

	Piece* getPiece(Color color)
	{
		auto iter = mapPiece.find(color);
		
		if (iter != mapPiece.end())
			return iter->second;
		else
		{
			Piece* ptr = nullptr; 
			
			if (color == Color::black)
				ptr = new Piece_Black;
			else
				ptr = new Piece_White;

			mapPiece.insert(make_pair(color , ptr));

			return ptr;
		}
	}
};

int main()
{
	Factory fact;

	fact.getPiece(black)->draw(Position(3, 4));
	fact.getPiece(white)->draw(Position(6, 9));

	return 0;
}

测试结果如下:

在这里插入图片描述

(17)代理模式 Proxy 。 比如把要访问的网站,当成一个对象。把对网站对象的直接操作(比如访问网站的行为 ) 改成对网站代理的访问,进而实现其它的附加控制:比如流量控制,密码控制等。代码如下:

class web
{
public:
	virtual ~web() {}  // 作为基类,析构函数一定要定义成虚函数。
	virtual void visit() = 0;
};

class Shopping : public web
{
public:
	void visit() { cout << " 访问了购物网站\n\n"; }
};

class Proxy : public web
{
private: web* ptrWeb;
public:
	Proxy(web* w) :ptrWeb(w) {}
	void visit() { ptrWeb->visit(); }
};


int main()
{
	Shopping siteShop;
	Proxy proxy(&siteShop);
	proxy.visit();

	return 0;
}

(18)

谢谢

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

多表查询实训

前提 本篇博客&#xff0c;我将通过讲解例题的方式&#xff0c;带大家进一步掌握多表查询的使用规则和使用技巧 正文 前提 先建好表 表1 salgrade (薪资等级表&#xff09; 表2 emp(员工信息表&#xff09; 表3 dept&#xff08;部门信息表&#xff09;&#xff0c;插入相…

图形处理单元(GPU)在现代计算中的应用与挑战(研究论文框架)

摘要:随着高性能计算需求的日益增长,图形处理单元(GPU)已从专业的图形渲染处理器转变为具有高性能并行处理能力的多功能计算平台。本文将探讨GPU的核心优势、编程模型、在不同领域的应用以及面临的挑战和限制。此外,还将讨论GPU技术的未来发展趋势和潜在的研究机会。 关键…

算法-位运算基础

文章目录 前置知识1. 交换两个数2. 比较两个数的大小3. leetcode268 寻找缺失的数字4. leetcode136 只出现一次的数字5. leetcode260 只出现一次的数字|||6. leetcode137 只出现一次的数字||7. 2/3的幂8. 大于等于该数字的最小2的幂9. leetcode201 数字范围按位与10. 位运算中分…

昇思MindSpore学习笔记4--数据集 Dataset

昇思MindSpore学习笔记4--数据集 Dataset 摘要&#xff1a; 昇思MindSpore数据集Dataset的加载、数据集常见操作和自定义数据集方法。 一、数据集 Dataset概念 MindSpore数据引擎基于Pipeline 数据预处理相关模块&#xff1a; 数据集Dataset加载原始数据&#xff0c;支持文本…

C#测试调用DotnetSpider爬取网页内容

微信公众号“DotNet”的文章《.NET快速实现网页数据抓取》介绍了调用开源网页爬取模块DotnetSpider爬取cnblog网站文章的基本方式。之前学习过使用HtmlAgilityPack抓取并分析网页内容&#xff0c;DotnetSpider也依赖HtmlAgilityPack模块&#xff0c;不过前者属于轻量、高效的爬…

基于OrangePi AIpro + owncloud 5分钟搭建一个私有网盘

OrangePi AIpro自带镜像系统已预装了docker&#xff0c;这里我们直接基于docker安装owncloud。 准备 切换用户&#xff1a; HwHiAiUser 默认密码&#xff1a;Mind123 su HwHiAiUser 创建文件夹 sudo mkdir /home/SummerGao/owncloud-docker-server 切换至刚创建的文件夹下…

1,Windows-本地Linux 系统(WSL)

目录 第一步电脑设置 第二步安装Ubuntu 第三文件传递 开发人员可以在 Windows 计算机上同时访问 Windows 和 Linux 的强大功能。 通过适用于 Linux 的 Windows 子系统 (WSL)&#xff0c;开发人员可以安装 Linux 发行版&#xff08;例如 Ubuntu、OpenSUSE、Kali、Debian、Arc…

AI赋能影视解说:Rap说唱玩法拆解!

在影视解说的领域&#xff0c;竞争一直非常激烈&#xff0c;众多创作者纷纷涌入这个热门的赛道。为了在众多声音中脱颖而出&#xff0c;创新成为了关键。最近&#xff0c;一种结合AI技术的解说方式——Rap说唱解说&#xff0c;以其新颖的形式和高效的创作过程&#xff0c;赢得了…

input子系统学习(一)

1、输入子系统框架 2、编写一个简单的设备驱动层代码 #include<linux/module.h> #include<linux/init.h> #include<linux/input.h> #include<linux/time.h>struct input_dev *my_input_dev;static void timer_function(struct timer_list *t); DEFINE…

【android 9】【input】【9.发送按键事件3——Inputchannel的创建过程】

系列文章 本人系列文章-CSDN博客 目录 系列文章 目录 1.简介 1.1 主要步骤 1.2 时序图 2.源码分析 2.1 WindowManagerImpl的addView 2.2 WindowManagerGlobal的addView 2.3 ViewRootImpl 2.4 getWindowSession 2.5 WMS中的openSession 2.6 Session 2.7 class W 2.…

【旭日x3派】部署官方yolov5全流程

地平线旭日x3派部署yolov5--全流程 前言一、深度学习环境安装二、安装docker三、部署3.1、安装工具链镜像3.2、配置天工开物OpenExplorer工具包3.3、创建深度学习虚拟空间&#xff0c;安装依赖&#xff1a;3.4、下载yolov5项目源码并运行3.5、pytorch的pt模型文件转onnx3.6、最…

【接口自动化测试】第三节.实现项目核心业务接口自动化

文章目录 前言一、实现登录接口对象封装和调用 1.0 登录接口的接口测试文档 1.1 接口对象层&#xff08;封装&#xff09; 1.2 测试脚本层&#xff08;调用&#xff09;二、课程新增接口对象封装和调用 2.0 课程新增接口的接口测试文档 2.1 接口对象层…

(单机版)神魔大陆|v0.51.0|冰火荣耀

前言 今天给大家带来一款单机游戏的架设&#xff1a;神魔大陆v0.51.0:冰火荣耀。 如今市面上的资源参差不齐&#xff0c;大部分的都不能运行&#xff0c;本人亲自测试&#xff0c;运行视频如下&#xff1a; (单机版)神魔大陆 下面我将详细的教程交给大家&#xff0c;请耐心阅…

gemini 1.5 flash (node项目)

https://www.npmjs.com/package/google/generative-ai https://ai.google.dev/pricing?hlzh-cn https://aistudio.google.com/app/apikey https://ai.google.dev/gemini-api/docs/models/gemini?hlzh-cn#gemini-1.5-flash https://ai.google.dev/gemini-api/docs/get-started…

【漏洞复现】学分制系统GetTimeTableData SQL注入

0x01 产品简介 学分制系统由上海鹏达计算机系统开发有限公司研发&#xff0c;是基于对职业教育特点和需求的深入理解&#xff0c;结合教育部相关文件精神&#xff0c;并广泛吸纳专家、学者意见而开发的一款综合性管理系统。系统采用模块化的设计方法&#xff0c;方便学校根据自…

[CAN] Intel 格式与 Motorola 格式的区别

编码格式 数据传输规则一、Intel 格式编码二、Motorola 格式编码三、分析总结🙋 前言 CAN 总线信号的编码格式有两种定义:Intel 格式与 Motorola 格式。究竟两种编码格式有什么样的区别呢?设计者、dbc 文件编辑者或者测试人员又该如何判断两种格式,并进行有效正确的配置和解…

独家原创 | Matlab实现CNN-Transformer多变量时间序列预测

SCI一区级 | Matlab实现BO-Transformer-GRU多变量时间序列预测 目录 SCI一区级 | Matlab实现BO-Transformer-GRU多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现CNN-Transformer多变量时间序列预测&#xff1b; 2.运行环境为Matlab2023b…

Android Focused Window的更新

启动App时更新inputInfo/请求焦点窗口流程&#xff1a; App主线程调ViewRootImpl.java的relayoutWindow()&#xff1b;然后调用到Wms的relayoutWindow()&#xff0c;窗口布局流程。焦点窗口的更新&#xff0c;通过WMS#updateFocusedWindowLocked()方法开始&#xff0c;下面从这…

熟练掌握爬虫技术

一、Crawler、Requests反爬破解 1. HTTP协议与WEB开发 1. 什么是请求头请求体&#xff0c;响应头响应体 2. URL地址包括什么 3. get请求和post请求到底是什么 4. Content-Type是什么1.1 简介 HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;…

安全架构概述_1.信息安全面临的威胁

在当今以计算机、网络和软件为载体的数字化服务几乎成为人类赖以生存的手段。与之而来的计算机犯罪呈现指数上升趋势&#xff0c;因此&#xff0c;信息的可用性、完整性、机密性、可控性和不可抵赖性等安全保障显得尤为重要&#xff0c;而满足这些诉求&#xff0c;离不开好的安…