施磊老师高级c++(五)

news2025/3/25 23:53:46

文章目录

    • 一、设计模式
    • 二、单例模式(创建型模式)- 重点(共三种代码)
      • 1.1 饿汉式单例模式 -- 不受欢迎
      • 1.2 懒汉式单例模式 -- 受欢迎
      • 1.3 线程安全的懒汉式单例模式--锁+volatile
    • 三、工厂模式(创建型模式)
      • 3.1 简单工厂模式
      • 3.2 工厂方法模式
      • 3.3 抽象工厂模式
      • 工厂模式总结--特点

单例模式与工厂模式

一、设计模式

设计模式是一种解决特定问题的预定义优秀代码框架,相较于自己摸索解决方案,它具有以下优点:

  1. 易维护:代码更易于维护,具有良好的可读性、复用性、可移植性和健壮性。
  2. 适应需求变化:设计模式的应用遵循 “开闭原则”(对修改关闭,对扩展开放),使得在需求变更或增加新功能时,能够灵活调整。
  3. 模块化设计:合理选择设计模式可以实现高内聚、低耦合的模块化设计,遵循软件设计的基本原则。

设计模式的分类:

  • 创建型模式:关注于对象的创建过程,尝试将对象的创建与使用分离,以增加系统的灵活性和可维护性
  • 结构型模式:关注于如何将类或对象组合成更大的结构,以解决更大的问题
  • 行为型模式:关注于对象之间的交互和职责分配,以实现更好的系统行为和更灵活的协作

23种设计模式:

  • 创建型模式(5种):单例模式(Singleton)、工厂方法模式(Factory Method)、抽象工厂模式(Abstract Factory)、建造者模式(Builder)、原型模式(Prototype)
  • 结构型模式(7种):适配器模式(Adapter)、桥接模式(Bridge)、装饰器模式(Decorator)、组合模式(Composite)、外观模式(Facade)、享元模式(Flyweight)、代理模式(Proxy)
  • 行为型模式(11种):模板方法模式(Template Method)、命令模式(Command)、迭代器模式(Iterator)、观察者模式(Observer)、中介者模式(Mediator)、备忘录模式(Memento)、访问者模式(Visitor)、状态模式(State)、策略模式(Strategy)、职责链模式(Chain of Responsibility)、解释器模式(Interpreter)

二、单例模式(创建型模式)- 重点(共三种代码)

在此之前, 先了解一下 static 关键字

static 用法作用补充说明
静态局部变量变量不会在函数调用结束后销毁,值会保留
变量在函数调用结束后依然存在(局部静态变量)
- 仅在定义它的函数内可见
- 初次声明时初始化一次,后续调用不会重新初始化
-会从栈区移动到数据区
静态全局变量仅在当前文件可见,防止命名冲突
限制变量作用范围,使其仅在当前文件可见(内部链接)
- 作用域限制在定义它的文件中,不会污染其他文件的命名空间
静态成员变量属于类,而不是对象,所有对象共享
变量属于类,而不是对象,所有对象共享一份数据
- 需在类内声明, 类外部定义和初始化 (ClassName::variableName = value;)
- 通过 类名::变量名 访问
静态成员函数属于类,不依赖对象,不能访问非静态成员
函数属于类,而不是对象,不能访问非静态成员
- 无 this 指针,不能访问实例成员变量/方法
- 通过 类名::函数名 访问
-其内部只能访问 静态 成员, 不能访问不同的成员
静态全局函数仅在当前文件可见,防止命名冲突
限制函数作用范围,使其仅在当前文件可见
- 仅在定义它的文件中可见,外部文件无法调用

单例模式:一个类不管创建多少次对象,永远只能得到该类类型的唯一一个实例对象,那么设计一个单例就必须要满足下面几个条件

  1. 构造函数私有化:通过将构造函数私有化,防止外部直接创建实例,从而控制实例的创建
  2. 定义该类的唯一实例:在类内部定义一个该类的静态实例并确保只有一个实例被创建
  3. 通过静态方法返回唯一实例:提供一个静态方法用于访问或获取这个唯一实例,确保每次调用返回相同的实例
  4. 删除拷贝构造和赋值运算符重载:防止通过拷贝构造函数或赋值操作符创建新的实例

单例模式分类:

  1. 饿汉式单例模式
    • 特点:实例在类加载时就被创建,无论是否需要使用实例
    • 优点:天然线程安全,因为实例在类加载过程中创建,不存在多线程访问问题
    • 缺点:即使没有使用实例,资源也会被占用,可能导致资源浪费
  2. 懒汉式单例模式
    • 特点:实例在第一次访问时才被创建,采用延迟加载机制
    • 优点:延迟实例化,只有在需要时才创建实例,节省资源
    • 缺点线程不安全,需要处理多线程环境中的同步问题,以确保实例的唯一性,可能影响性能

单例模式的应用场景举例:

  • 日志模块:整个应用通常只需要一个日志模块实例,以统一管理日志的输出
  • 数据库模块:在客户端和服务器端之间进行通信时,使用单例模式可以确保只有一个数据库连接实例,从而减少资源消耗和连接管理的复杂性
  • 配置管理:应用程序中配置数据通常是全局的,并且需要统一访问,可以使用单例模式来管理
  • 线程池:使用单例模式可以确保只有一个线程池实例,便于统一管理和调度线程
  • 缓存:单例模式可以用于实现应用的全局缓存,以提高访问速度和性能

1.1 饿汉式单例模式 – 不受欢迎

  1. 什么是饿汉式单例模式?
    饿汉式单例(Hungry Singleton)是一种在类加载时就立即实例化对象的单例模式

    还没有获取实例对象, 实例对象 就已经产生了

  2. 饿汉式 一定是 线程安全的?

    因为 静态的成员变量 在数据段(.data), 数据段 程序已启动 就初始化好了

    饿汉式单例本身在静态变量的初始化中一般是线程安全的,但需要注意静态初始化顺序的问题,尤其在多线程环境和动态库情况下。为了确保绝对的线程安全,可以使用一些额外的同步机制(例如 std::call_once 或互斥锁)来避免潜在的竞争条件。

  3. 缺点:

    资源浪费(主要):即使单例未被使用,类加载时就会创建实例,导致不必要的资源消耗。

    不支持延迟初始化:实例在程序启动时就创建,无法根据需要延迟创建。

    初始化顺序问题:在静态变量初始化时可能会引发顺序问题,导致错误或未定义行为。

    无法处理复杂并发需求:对复杂资源或多线程环境下的初始化需求处理不足。

    生命周期管理困难:无法灵活控制单例的销毁和生命周期,难以处理动态加载和卸载。

代码示例:

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
#include <queue>
#include <condition_variable>
using namespace std;

class Singleton
{
public:
	// 3. 提供一个静态方法返回唯一实例的引用
	static Singleton* getInstance() { return &instance; }

private:
	static Singleton instance;	// 2. 定义该类的唯一实例对象(使用静态变量,在数据段上)
	Singleton() { cout << "Singleton()" << endl; }	// 1.构造函数私有化
	~Singleton() { cout << "~Singleton()" << endl; }

	// 4. 删除拷贝构造和赋值函数 - 不能让他使用默认的
	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;
};

Singleton Singleton::instance;	// 类外初始化静态成员变量

int main()
{
    // 还没有调用, 实例对象就创建了
	Singleton* p1 = Singleton::getInstance(); // 静态成员函数, 需要使用 类名::函数名 使用
	Singleton* p2 = Singleton::getInstance(); 
	Singleton* p3 = Singleton::getInstance();

	//Singleton t = *p1;  // 单例模式不允许, 需要删除类内 拷贝和赋值函数

	return 0;
}



测试结果:

Singleton()
008EE1E0
008EE1E0
008EE1E0
~Singleton()

可以看到,该程序通过饿汉式单例模式实现了单例的创建和管理,确保了整个程序中Singleton类只有一个实例。程序输出验证了单例模式的正确性,所有获取的引用都指向同一个实例

1.2 懒汉式单例模式 – 受欢迎

  1. 什么是懒汉式单例?

    懒汉式单例(Lazy Singleton)是单例设计模式的另一种实现方式,与饿汉式单例不同,它是在第一次需要实例化时才创建对象,而不是在程序启动时就立即创建。

代码示例:

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
#include <queue>
#include <condition_variable>
using namespace std;

class Singleton
{
public:
	
	static Singleton* getInstance() 
	{
		if (instance == nullptr)  //#3 延迟实例化
		{
			instance = new Singleton();
		}
		return instance; 
	}
	static void destroyInstance()
	{
		delete instance;
	}

private:
	static Singleton* instance;	  // #1 修改为指针, 更好的是使用智能指针, 为了自动析构, 这种一般指针, 还得写 销毁函数, 手动释放
	Singleton() { cout << "Singleton()" << endl; }	
	~Singleton() { cout << "~Singleton()" << endl; }


	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;
};

Singleton* Singleton::instance=nullptr;	// #2 初始化为空

int main()
{
	Singleton* p1 = Singleton::getInstance(); 
	Singleton* p2 = Singleton::getInstance(); 
	Singleton* p3 = Singleton::getInstance();


	cout << p1 << endl;
	cout << p2 << endl;
	cout << p3 << endl;

	Singleton::destroyInstance();

	return 0;
}

测试结果:

Singleton()
00F20548
00F20548
00F20548
~Singleton()

1.3 线程安全的懒汉式单例模式–锁+volatile

  1. 可重入函数(Reentrant Function)是指在多线程或中断处理的环境下,函数能够安全地被多个线程或中断同时调用,即使在执行过程中该函数被再次调用,也能保证不会产生数据不一致或程序崩溃

  2. 上面实现的懒汉式单例模式是有问题

    其中getInstance函数不是可重入函数

    根源在于:

    会有线程安全的问题getInstance三个步骤:开辟内存、构造对象、给instance赋值(编译器翻译成汇编指令的顺序或者也可以是开辟内存、给instance赋值、构造对象), 不是原子操作

无论两种情况中的哪种,只要是线程一在给instance赋值之前,如果有线程二进入此函数,就会造成线程不安全。

加锁的懒汉单例

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
#include <queue>
#include <condition_variable>
using namespace std;

std::mutex mtx;
class Singleton
{
public:
	
	static Singleton* getInstance() 
	{
		//lock_guard<std::mutex> guard(mtx);  // 这个位置 锁力度太大
		if (instance == nullptr)  
		{
			lock_guard<std::mutex> guard(mtx); // 只在第一次实例化时 加锁, 这有这一块 是步骤多的, 不是原子操作
			// 加锁后, 还要判断
			if (instance == nullptr)
			{
				instance = new Singleton();
			}
			
		}
		return instance; 
	}
	static void destroyInstance()
	{
		delete instance;
	}

private:
	static Singleton *volatile instance;	  // 同时要保证 不缓存
	Singleton() { cout << "Singleton()" << endl; }	
	~Singleton() { cout << "~Singleton()" << endl; }


	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;
};

Singleton * volatile Singleton::instance=nullptr;

int main()
{
	Singleton* p1 = Singleton::getInstance(); 
	Singleton* p2 = Singleton::getInstance(); 
	Singleton* p3 = Singleton::getInstance();


	cout << p1 << endl;
	cout << p2 << endl;
	cout << p3 << endl;

	Singleton::destroyInstance();

	return 0;
}

instance加一个volatile,这是给指针加的(不是给指针的指向加的)。好处是当一个线程对instance赋值时,其他线程马上均能看到instance的改变。因为线程现在已经不对共享变量进行缓存了,大家看的都是其原始内存中的值

非互斥锁的线程安全懒汉式单例模式

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
#include <queue>
#include <condition_variable>
using namespace std;

std::mutex mtx;
class Singleton
{
public:
	
	static Singleton* getInstance() 
	{
		static Singleton instance;
		return &instance; 
	}


private:
		
	Singleton() { cout << "Singleton()" << endl; }	
	~Singleton() { cout << "~Singleton()" << endl; }


	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;
};


int main()
{
	Singleton* p1 = Singleton::getInstance(); 
	Singleton* p2 = Singleton::getInstance(); 
	Singleton* p3 = Singleton::getInstance();


	cout << p1 << endl;
	cout << p2 << endl;
	cout << p3 << endl;


	return 0;
}

函数静态局部变量的初始化在汇编指令上已经自动添加线程互斥指令了,也就是已经线程安全了!(linux下 gdb调试, 看底层汇编, 看老师博客) vs里看汇编是看不到的

在 C++11 及以后的标准中,局部静态变量的初始化线程安全的

对于static静态局部变量的初始化,编译器会自动对它的初始化进行加锁和解锁控制,使静态局部变量的初始化成为线程安全的操作,不用担心多个线程都会初始化静态局部变量,因此上面的懒汉单例模式是线程安全的单例模式!

三、工厂模式(创建型模式)

主要用于 创建对象 非常多的 时候

先了解一下工厂模式

工厂模式是一个比较常用的创建型设计模式,主要是封装了对象的创建,其中可以细分为三种:简单工厂模式(Simple Factory)、工厂方法模式(Factory Method)、抽象工厂模式(Abstract Factory)

3.1 简单工厂模式

简单工厂模式:

  • 定义:简单工厂模式只有一个工厂类,通过该工厂类的静态方法来创建具体的产品对象。工厂类根据不同的参数决定实例化哪一个产品类(简单工厂模式不属于标准OOP设计模式中的一项)
  • 适用场景:适用于产品种类较少且不经常扩展的场合。可以快速创建不同的产品对象,但扩展性有限

代码核心:
枚举类和简单工厂类

#include <iostream>
#include <memory>
using namespace std;

class Car
{
public:
	Car(string name) : _name(name) {}
	virtual void show() = 0;
protected:
	string _name;
};

class Bmw : public Car
{
public:
	Bmw(string name) : Car(name) {}
	void show() override { cout << "我是宝马:" << _name << endl; }
};

class Audi : public Car
{
public:
	Audi(string name) : Car(name) {}
	void show() override { cout << "我是奥迪:" << _name << endl; }
};

enum CarType  // 枚举值
{
	BMW, AUDI
};

class SimpleFactory   // 简单工厂的 核心
{
public:
	static Car* createCar(CarType ct)
	{
		switch (ct)
		{
		case BMW:
			return new Bmw("X3");
		case AUDI:
			return new Audi("A8");
		default:
			cerr << "传入参数不正确" << ct<< endl;
			return nullptr;
		}
	}
};

int main()
{
	// 买车, 不需要知道车是怎么构造的
	//Car* p1 = new Bmw("Bmw X1"); //使用的时候, 需要记住 很多 派生类名

	// Car* p1 = SimpleFactory::createCar(BMW);  
	// Car* p2 = SimpleFactory::createCar(AUDI);
	// if (p1) p1->show();
	// if (p2) p2->show();
	// delete p1;
	// delete p2;

	// 改成智能指针,自动释放资源, 注意需要头文件memory
	unique_ptr<Car> p1(SimpleFactory::createCar(BMW));
	unique_ptr<Car> p2(SimpleFactory::createCar(AUDI));
	if (p1) p1->show();
	if (p2) p2->show();

	return 0;
}

现在,简单工厂模式就实现了,但是这种方法有一些缺陷,因为同一个工厂不会又造宝马又造奥迪,又造手机又造键盘的,这一般不符合实际的情况,而且最重要的是这个工厂不符合“开闭原则”,如果我们要增删车辆,就要修改接口,这样很不好。

基于这样的缺陷,接下来看看工厂方法模式

3.2 工厂方法模式

工厂方法模式:

  • 定义:工厂方法模式由一个抽象工厂类和多个具体工厂类组成。每个具体工厂类负责创建一个具体产品对象。通过继承抽象工厂类的方法,可以多态地创建不同的具体产品
  • 适用场景:适用于某个产品种类中包含多个具体产品的情况。能够通过增加新的工厂类来扩展产品系列

代码核心: 工厂方法类(虚构造函数)及其派生类

#include <iostream>
#include <memory>
using namespace std;

class Car
{
public:
	Car(string name) : _name(name) {}
	virtual void show() = 0;
protected:
	string _name;
};

class Bmw : public Car
{
public:
	Bmw(string name) : Car(name) {}
	void show() override { cout << "我是宝马:" << _name << endl; }
};

class Audi : public Car
{
public:
	Audi(string name) : Car(name) {}
	void show() override { cout << "我是奥迪:" << _name << endl; }
};

// 工厂方法
class Factory
{
public:
	virtual Car* createCar(string name) = 0; // 工厂方法
};
// 宝马工厂
class BMWFactory : public Factory
{
public:
	Car* createCar(string name) override { return new Bmw(name); }
};
// 奥迪工厂
class AudiFactory : public Factory
{
public:
	Car* createCar(string name) override { return new Audi(name); }
};

int main()
{
	// 这个构建有点麻烦, 慢慢看, 先创建相应的工厂, 在使用工厂创建相应的产品

	//unique_ptr<Factory> bmwfty(new BMWFactory());
	unique_ptr<Factory> bmwfty = make_unique<BMWFactory>() ; // c++14 new在外面是不行的
	unique_ptr<Factory> audifty(new AudiFactory());

	unique_ptr<Car> p1(bmwfty->createCar("X6"));
	unique_ptr<Car> p2(audifty->createCar("A8"));
	p1->show();
	p2->show();

	return 0;
}

现在符合“开闭原则”,如果现在想加一个奔驰工厂,直接增加BenzFactory类就行了

3.3 抽象工厂模式

抽象工厂模式:

  • 定义:抽象工厂模式由一个抽象工厂类和多个具体工厂类组成,同时有多个产品接口或抽象类。每个具体工厂类可以创建一组相关的产品对象
  • 适用场景:适用于涉及多个产品种类的复杂系统,可以创建一组相关或依赖的产品对象。适合于需要创建多个系列产品的情况

工厂方法与抽象工厂区别:工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。因此,工厂方法模式可以被视为抽象工厂模式的一个特例或简化形式

当一个工厂不止生产车, 还生产对应的灯, 即一组产品

还有缺点: 基类添加新产品时, 派生类也得加

#include <iostream>
#include <memory>
using namespace std;

class Car {
public:
	virtual void show() = 0;
};

class Light {
public:
	virtual void type() = 0;
};
// ===================================================
class BMWCar : public Car {
public:
	void show() override { cout << "BMW car" << endl; }
};

class BMWLight : public Light {
public:
	void type() override { cout << "BMW Light" << endl; }
};
// ===================================================
class AudiCar : public Car {
public:
	void show() override { cout << "Audi car" << endl; }
};

class AudiLight : public Light {
public:
	void type() override { cout << "Audi Light" << endl; }
};
// ===================================================
class AbstractFactory {
public:	// 产品簇
	virtual Car* createCar() = 0;
	virtual Light* createLight() = 0;
};

class BMWFactory : public AbstractFactory {
public:
	Car* createCar() override { return new BMWCar(); }
	Light* createLight() override { return new BMWLight(); }
};

class AudiFactory : public AbstractFactory {
public:
	Car* createCar() override { return new AudiCar(); }
	Light* createLight() override { return new AudiLight(); }
};
// ===================================================
int main()
{
	// 创建具体工厂
	unique_ptr<AbstractFactory> bmwfty(new BMWFactory());
	unique_ptr<AbstractFactory> audifty(new AudiFactory());

	// 使用工厂创建产品
	unique_ptr<Car> bmwCar(bmwfty->createCar());
	unique_ptr<Light> bmwLight(bmwfty->createLight());
	unique_ptr<Car> audiCar(audifty->createCar());
	unique_ptr<Light> audiLight(audifty->createLight());
	if (bmwCar) bmwCar->show();
	if (bmwLight) bmwLight->type();
	if (audiCar) audiCar->show();
	if (audiLight) audiLight->type();

	return 0;
}

工厂模式总结–特点

简单工厂 (Simple Factory)

  • 把对象的创建封装在一个接口函数里面,通过传入不同的标识,返回创建的对象。
  • 客户不用自己负责 new 对象,不用了解对象创建的详细过程。
  • 提供创建对象实例的接口函数不闭合,不能对修改关闭

工厂方法 (Factory Method)

  • Factory 基类,提供了一个纯虚函数(创建产品),定义派生类(具体产品的工厂)负责创建对应的产品。
  • 可以做到不同的产品,在不同的工厂里面创建,能够对现有工厂,以及产品的修改关闭。
  • 实际上,很多产品是有关联关系的,属于一个产品簇,不应该放在不同的工厂里面去创建,这样:
    • 一是不符合实际的产品对象创建逻辑。
    • 二是工厂类太多了,不好维护。

抽象工厂 (Abstract Factory)

  • 把有关联关系的,属于一个产品簇的所有产品创建的接口函数,放在一个抽象工厂里面 AbstractFactory
  • 派生类(具体产品的工厂)应该负责创建该产品簇里面所有的产品。

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

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

相关文章

阿里云对象存储教程

搜“对象存储->免费试用” 选择你的心仪产品&#xff0c;我使用的是第一个 创建后获得三个实例&#xff1a; 点击右上角自己的账号可以进入到AccessKey管理界面 回到对象存储控制台创建Bucket实例 在以下文件中替换自己Bucket的信息即可美美使用~ package com.kitty.blog…

【Node.js入门笔记10---http 模块】

Node.js入门笔记10 Node.js---http 模块一、核心功能0.学习http的前提1. 创建 HTTP 服务器2. 处理请求和响应 二、进阶用法1. 路由管理2. 处理 POST 请求3. 中间件模式 三、常见场景四、错误处理与安全五、对比 http 与 Express六、工具库推荐&#xff1a; Node.js—http 模块 …

实验11 机器学习-贝叶斯分类器

实验11 机器学习-贝叶斯分类器 一、实验目的 &#xff08;1&#xff09;理解并熟悉贝叶斯分类器的思想和原理&#xff1b; &#xff08;2&#xff09;熟悉贝叶斯分类器的数学推导过程&#xff1b; &#xff08;3&#xff09;能运用贝叶斯分类器解决实际问题并体会算法的效果&a…

OpenHarmony子系统开发 - 电池管理(二)

OpenHarmony子系统开发 - 电池管理&#xff08;二&#xff09; 五、充电限流限压定制开发指导 概述 简介 OpenHarmony默认提供了充电限流限压的特性。在对终端设备进行充电时&#xff0c;由于环境影响&#xff0c;可能会导致电池温度过高&#xff0c;因此需要对充电电流或电…

hive 数据简介

Hive介绍 1&#xff09;Hive简介 Hive是基于Hadoop的一个数据仓库工具&#xff0c;用于结构化数据的查询、分析和汇总。Hive提供类SQL查询功能&#xff0c;它将SQL转换为MapReduce程序。 Hive不支持OLTP&#xff0c;Hive无法提供实时查询。 2&#xff09;Hive在大数据生态环境…

Win32桌面编程:ACLUI.DLL,EditSecurity(IntPtr hwndOwner, ISecurityInformation psi)

在Windows编程中&#xff0c;我们通常需要借助通用对话框的力量&#xff0c;今天我们就聊一下“安全属性表”通用对话框的使用心得。 当我们调用EditSecurity函数时&#xff1a; 1.EditSecurity将调用ISecurityInformation中的GetObjectInformation函数 在编写 ISecurityInf…

数据分析异步进阶:aiohttp与Asyncio性能提升

一、时间轴呈现方案进程 2023-04-01&#xff1a;需求确认 确定目标&#xff1a;使用aiohttp与Asyncio提升采集性能&#xff0c;目标采集今日头条网站的新闻数据&#xff08;标题、内容、时间等&#xff09;。同时要求在程序中加入代理IP、Cookie和UserAgent的设置&#xff0c;…

《AI大模型趣味实战 》第8集:多端适配 个人新闻头条 基于大模型和RSS聚合打造个人新闻电台(Flask WEB版) 2

《AI大模型趣味实战 》第8集&#xff1a;多端适配 个人新闻头条 基于大模型和RSS聚合打造个人新闻电台(Flask WEB版) 2 摘要 本文末尾介绍了如何实现新闻智能体的方法。在信息爆炸的时代&#xff0c;如何高效获取和筛选感兴趣的新闻内容成为一个现实问题。本文将带领读者通过P…

低配电脑畅玩《怪物猎人:荒野》,ToDesk云电脑优化从30帧到144帧?

《怪物猎人&#xff1a;荒野&#xff08;Monster Hunter Wilds&#xff09;》自2025年正式发售以来已取得相当亮眼的成绩&#xff0c;仅用三天时间便轻松突破800万销量&#xff0c;目前顺利蝉联周榜冠军&#xff1b;凭借着开放世界的宏大场景和丰富的狩猎玩法&#xff0c;该游戏…

【js逆向入门】图灵爬虫练习平台 第九题

地址&#xff1a;aHR0cHM6Ly9zdHUudHVsaW5ncHl0b24uY24vcHJvYmxlbS1kZXRhaWwvOS8 f12进入了debugger&#xff0c;右击选择一律不在此处暂停&#xff0c; 点击继续执行 查看请求信息 查看载荷&#xff0c;2个加密参数&#xff0c;m和tt 查看启动器&#xff0c;打上断点 进来 往…

NET6 WebApi第5讲:中间件(源码理解,俄罗斯套娃怎么来的?);Web 服务器 (Nginx / IIS / Kestrel)、WSL、SSL/TSL

一、NET6的启动流程 区别&#xff1a; .NET6 WebApi第1讲&#xff1a;VSCode开发.NET项目、区别.NET5框架【两个框架启动流程详解】_vscode webapi-CSDN博客 2、WebApplicationBuilder&#xff1a;是NET6引入的一个类&#xff0c;是建造者模式的典型应用 1>建造者模式的…

Nginx及前端部署全流程:初始化配置到生产环境部署(附Nginx常用命令)

nginx&前端从初始化配置到部署&#xff08;xshell&#xff09; 前言下载nginx前端打包与创建具体文件夹路径配置nginx.nginx.conf文件配置项内容 配置nginx.service文件配置项内容 启动nginx常用nginx命令 前言 目标&#xff1a;在xshell中部署前端包。 第一步&#xff1a…

python 实现一个简单的window 任务管理器

import tkinter as tk from tkinter import ttk import psutil# 运行此代码前&#xff0c;请确保已经安装了 psutil 库&#xff0c;可以使用 pip install psutil 进行安装。 # 由于获取进程信息可能会受到权限限制&#xff0c;某些进程的信息可能无法获取&#xff0c;代码中已经…

【xiaozhi赎回之路-2:语音可以自己配置就是用GPT本地API】

固件作用 打通了网络和硬件的沟通 修改固件实现【改变连接到小智服务器的】 回答逻辑LLM自定义 自定义了Coze&#xff08;比较高级&#xff0c;自定义程度比较高&#xff0c;包括知识库&#xff0c;虚拟脚色-恋人-雅思老师-娃娃玩具{可能需要使用显卡对开源模型进行微调-产…

WX小程序

下载 package com.sky.utils;import com.alibaba.fastjson.JSONObject; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.Cl…

Spring boot 3.4 后 SDK 升级,暨 UI API/MCP 计划

PS 写这篇文章后看到 A Deep Dive Into MCP and the Future of AI Tooling | Andreessen HorowitzWe explore what MCP is, how it changes the way AI interacts with tools, what developers are already building, and the challenges that still need solving. https://a1…

Linux下JDK1.8安装配置

目录 1.下载完上传到Linux系统中 2.解压JDK压缩包 3.配置JDK环境变量 4.设置环境变量生效 5.查看环境变量是否配置成功 官网下载地址:Java Downloads | Oracle 1.下载完上传到Linux系统中 2.解压JDK压缩包 tar -zxvf jdk-8u151-linux-x64.tar.gz -C /usr/local (解压…

Python OCR文本识别详细步骤及代码示例

光学字符识别&#xff08;OCR&#xff09;是将图像中的文字转换为可编辑文本的技术。在Python中&#xff0c;我们可以利用多种库实现OCR功能。本文将详细介绍使用Tesseract和EasyOCR进行文本识别的步骤&#xff0c;并提供完整的代码示例。 一、OCR简介 OCR&#xff08;Optical…

Linux固定IP方法(RedHat+Net模式)

1、查看当前网关 ip route | grep default 2、配置静态IP 双击重启 3、验证

210、【图论】课程表(Python)

题目 思路 这道题本质上是一个拓扑排序。每次先统计每个点的入度个数、然后再统计点与点之间的邻接关系&#xff0c;找到入度为0的点作为起始遍历点。之后每遍历到这个点之后&#xff0c;就把这个点后续的邻接关系边的点入度减去一。当某个点入度为0时&#xff0c;继续被加入其…