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

news2024/11/23 3:06:03

(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)

谢谢

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

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

相关文章

二叉树的层序遍历/后序遍历(leetcode104二叉树的最大深度、111二叉树的最小深度)(华为OD悄悄话、数组二叉树)

104二叉树的最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 本题可以使用前序&#xff08;中左右&#xff09;&#xff0c;也可以使用后序遍历&#xff08;左右中&#xff09;&#xff0c;…

自闭症早期风险判别和干预新路径

谷禾健康 自闭症谱系障碍 (ASD) 是一组神经发育疾病&#xff0c;其特征是社交互动和沟通的质量障碍、兴趣受限以及重复和刻板行为。 环境因素在自闭症中发挥重要作用&#xff0c;多项研究以及谷禾队列研究文章表明肠道微生物对于自闭症的发生和发展以及存在明显的菌群和代谢物的…

JVM专题十一:JVM 中的收集器一

上一篇JVM专题十&#xff1a;JVM中的垃圾回收机制专题中&#xff0c;我们主要介绍了Java的垃圾机制&#xff0c;包括垃圾回收基本概念&#xff0c;重点介绍了垃圾回收机制中自动内存管理与垃圾收集算法。如果说收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回…

nginx优势以及应用场景,编译安装和nginx

一. Nginx是什么&#xff1f; 1. Nginx概述 高性能、轻量级Web服务软件系统资源消耗低对HTTP并发连接的处理能力高单台物理服务器可支持30,000&#xff5e;50,000个并发请求Nginx&#xff08;发音同 “engine x”&#xff09;是一个高性能的反向代理和Web服务器软件&#xff0c…

MySQL之覆盖索引

什么是覆盖索引&#xff1f; 覆盖索引&#xff1a;查询时使用了索引&#xff0c;且需要返回的列&#xff0c;在改索引中已经全部能找到。 示例&#xff1a;有user表如下&#xff1a; CREATE TABLE user (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 技术主键,name varch…

Windows 中的 Hosts 文件是什么?如何找到并修改它?

什么是 Hosts 文件 Hosts 文件是一个纯文本文件&#xff0c;存在于几乎所有的操作系统中&#xff0c;用于将主机名映射到 IP 地址。在域名系统&#xff08;DNS&#xff09;尚未普及之前&#xff0c;Hosts 文件是计算机网络中唯一用于主机名解析的方式。随着网络规模的扩大和 D…

GPT-4替代大学生参加考试,94%成功作弊未被发现!

目录 01 「伪装」过程 02 实验结果 03 成绩如何&#xff1f; 调查显示&#xff0c;94%的AI生成内容完全不会被大学教授察觉。 而且在83.4%的情况下&#xff0c;「AI同学」的成绩显著高于人类学生。 看来&#xff0c;AI真的要攻陷人类的考试了。 其实&#xff0c;早在GPT-4发…

【Mybatis】Mybatis初识-通过源码学习执行流程

文章目录 1.Mybatis核心组件1.1 SqlSession1.2 SqlSessionFactory1.3 Mapper1.4 MappedStatement1.5 Executor 2. Mybatis各组件之间关系3. 构建SqlSessionFactory3.1 从XML文件中构建3.2 不使用XML构建SqlSessionFactory 4. 如何从SqlSessionFactory获取SqlSession5.获取Mappe…

STM32CubeMx的学习记录系列(1) - 软件的下载与点灯

目录 因为最近要学STM32的嵌入式AI开发&#xff0c;但它于是基于STM32CubeMX开发的&#xff0c;就顺便把这个学了。 直接百度STM32CubeMX&#xff0c;到意法的官网去下载。下载过程就看这篇博客 https://blog.csdn.net/as480133937/article/details/98885316 点灯 选择芯片&…

PG备份与恢复

一、开启WAL归档 1、创建归档目录 我们除了存储数据目录pgdata之外&#xff0c;还要创建backups&#xff0c;scripts&#xff0c;archive_wals文件 mkdir -p /home/mydba/pgdata/arch mkdir -p /home/mydba/pgdata/scripts mkdir -p /home/mydba/backups chown -R mydba.myd…

PIP一些问题解决办法

研究生期间遇到关于PIP一些问题报错以及解决办法的汇总 pip安装报错&#xff1a;is not a supported wheel on this platform 本节转自 https://blog.csdn.net/happywlg123/article/details/107281936 ​ 出现这个问题&#xff0c;是由于这个whl和系统python版本不匹配导致的。…

数字人解决方案——数字人类不仅仅是长着一张脸的人工智能

数字人类曾经是简单的聊天机器人&#xff0c;经常误解问题&#xff0c;这让许多人感到沮丧。现在&#xff0c;他们已经发展成为先进的虚拟代理&#xff0c;可以像最好的客户服务代表一样有效地沟通&#xff0c;拥有专家级的知识&#xff0c;并且看起来与真人惊人地相似。 这些…

基于协同过滤的电影推荐与大数据分析的可视化系统

基于协同过滤的电影推荐与大数据分析的可视化系统 在大数据时代&#xff0c;数据分析和可视化是从大量数据中提取有价值信息的关键步骤。本文将介绍如何使用Python进行数据爬取&#xff0c;Hive进行数据分析&#xff0c;ECharts进行数据可视化&#xff0c;以及基于协同过滤算法…

<电力行业> - 《第7课:发电》

1 发电的原理 电力生产的发电环节是利用电能生产设备将各种一次能源或其他形式的能转换为电能。生产电能的主要方式有火力发电、水力发电、核能发电、地热发电、风力发电、太阳能发电、潮汐能发电、生物智能发电和燃料电池发电等。 除太阳能发电的光伏电池技术和燃料电池发电…

[单机版架设]新天堂2-死亡骑士338|带AI机器人

前言 今天给大家带来一款单机游戏的架设&#xff1a;新天堂2-死亡骑士338单机服务端—带AI机器人 如今市面上的资源参差不齐&#xff0c;大部分的都不能运行&#xff0c;本人亲自测试&#xff0c;运行视频如下&#xff1a; 新天堂2 搭建教程 此游戏架设不需要虚拟机&#xf…

利用LLM本身训练SoTA embedding模型

今天分享一篇Microsoft公司的一篇文章&#xff0c;Title: Improving Text Embeddings with Large Language Models&#xff1a;使用大语言模型改善文本嵌入。 这篇文章探索了直接利用LLM来做embedding模型&#xff0c;其只需要利用合成数据和少于1000次的训练步骤就能获得高质…

Arthas快速入门

简介 Arthas 是一款线上监控诊断产品&#xff0c;通过全局视角实时查看应用 load、内存、gc、线程的状态信息&#xff0c;并能在不修改应用代码的情况下&#xff0c;对业务问题进行诊断&#xff0c;包括查看方法调用的出入参、异常&#xff0c;监测方法执行耗时&#xff0c;类…

仓库管理系统12--供应商设置

1、添加供应商窗体 2、布局控件UI <UserControl x:Class"West.StoreMgr.View.SupplierView"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc"http://…

什么是机器学习,机器学习与人工智能的区别是什么(一)?

人工智能和计算机游戏领域的先驱阿瑟塞缪尔&#xff08;Arthur Samuel&#xff09;创造了 "机器学习"一词。他将机器学习定义为 “一个让计算机无需明确编程即可学习的研究领域” 。通俗地说&#xff0c;机器学习&#xff08;ML&#xff09;可以解释为根据计算机的经…

前端学习笔记(2406261):jquery使用checkbox控制页面自动刷新

文章目录 需求登录页面主页面 API用户登录login获取数据getdata 代码登录页面主页面 关于后端 需求 这是一个物联网的演示项目&#xff0c;web端能够实时显示后台数据的变化&#xff0c;其流程非常简单&#xff1a; 用户登录登录成功后显示主界面面主界面进入后自动显示数据数…