设计模式-单例模式工厂模式

news2024/11/24 12:50:18

3.1 单例模式

1.概念

用类来实现单例。由于某种需要,要保证一个类在程序的生命周期中只有一个实例,并且提供该实例的全局访问方法。

2.结构三要素

1)私有的静态对象属性private static instance,它的类型就是当前类的对象,静态的特性决定了程序一启动就要初始化完成当前对象的构造。

2)私有的构造函数(保证在程序中,无法通过new的方式来创建对象实例,只能用于类内部创建该单例对象)

3)公有的,静态的(类可以直接访问,因为无法创建对象,所以不能用对象来访问非静态的成员函数。),访问该实例对象的方法public static Singleton getInstance(){}

3.实现——饿汉式(代码见vs)

饿汉式就是应用程序刚启动时,不管外部有没有调用该类的实例方法,该类的实例就已经创建好了。以空间换时间。

优点:写法简单,在多线程下能保证单例实例的唯一性,运行效率高。

缺点:在外部未使用到该类时,类的实例已经创建,若类实例的创建比较消耗系统资源,并且外部一直没有调用该实例,造成资源浪费。

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

//饿汉式
class Singleton
{
private:
    static Singleton* instance;//1)私有的静态对象属性
    Singleton() {};//2)私有的构造函数
public:
    static Singleton* getInstance()//3)公有的,静态的访问该单例的方法
    {
        return instance;
    }
};
//实例化类的静态成员,要在类外初始化
Singleton* Singleton::instance = new Singleton();//程序一启动,单例马上就创建出来了,并且在整个程序生命周期,只有一份
void test01()
{
    //测试一下,单例是否生效
    Singleton* ins=Singleton::getInstance();
    Singleton* ins2=Singleton::getInstance();
    //接下来通过查看ins和ins2的地址,就可以判断是否为同一个对象
    cout << ins << "=" << ins2 << endl;
}

4.实现——懒汉式(代码见vs)

懒汉式就是应用程序刚启动时,并不创建实例,当外部调用该类的实例或者该类实例方法时,才创建该类的实例。是以时间换空间。

优点:实例在被使用时创建,可以节省系统资源,体现延迟加载的思想。

缺点:系统刚启动且未被外部调用时,实例没有创建,如果同时有多个线程调用实例方法getInstance,可能会产生多个实例。在多线程下,不能保证单例实例的唯一性,需使用同步,同步会导致多线程下争夺锁资源,降低运行效率。

//懒汉式
class Singleton_Lan
{
private:
    static Singleton_Lan* instance;
    Singleton_Lan() {};
public:
    static Singleton_Lan* getInstance()
    {
        //把单例的创建时机放到这里,有人调用这个函数的时候,就要创建了
        if (instance==nullptr)//加个判断,当单例没有被创建的时候,才去创建它
        {
            instance = new Singleton_Lan();//这里创建出单例
        }
        return instance;
    }
};
void test02()
{
    //测试一下,单例是否生效
    Singleton_Lan* ins = Singleton_Lan::getInstance();
    Singleton_Lan* ins2 = Singleton_Lan::getInstance();
    //接下来通过查看ins和ins2的地址,就可以判断是否为同一个对象
    cout << ins << "=" << ins2 << endl;
}
Singleton_Lan* Singleton_Lan::instance = nullptr;//懒汉式,程序启动的时候不创建单例,而是设置为空

5.验证懒汉模式下——多线程不安全问题(代码见vs)

//多线程下,懒汉模式不安全,无法保证单例的实现
class Singleton_Duo
{
private:
    static Singleton_Duo* instance;
    Singleton_Duo() { this_thread::sleep_for(chrono::milliseconds(500)); };//构造的时候加延时,这个时候就可以发现问题
public:
    static Singleton_Duo* getInstance()
    {
        if (instance==nullptr)//这个判断,在多线程下是不可靠的
        {
            instance = new Singleton_Duo();
        }
        return instance;
    }
};
Singleton_Duo* Singleton_Duo::instance = nullptr;
//准备线程绑定的函数
void threadFunc()
{
    Singleton_Duo* ins=Singleton_Duo::getInstance();
    cout << this_thread::get_id() << ":" << ins << endl;
}
void test03()
{
    thread t3[3];
    for (int i = 0; i < 3; i++)
    {
        t3[i] = thread(threadFunc);
    }
    for (int i = 0; i < 3; i++)
    {
        t3[i].join();
    }
}
//如果换成饿汉式单例,多线程下也是安全的
void threadFunc_e()
{
    Singleton* ins = Singleton::getInstance();
    cout << this_thread::get_id() << ":" << ins << endl;
}
void test04()
{
    thread t3[3];
    for (int i = 0; i < 3; i++)
    {
        t3[i] = thread(threadFunc_e);
    }
    for (int i = 0; i < 3; i++)
    {
        t3[i].join();
    }
}

6.懒汉式——加锁模式(代码见vs)

//通过加锁,解决多线程下懒汉式单例的问题
mutex mut;//锁对象
class Singleton_Duo_Suo
{
private:
    static Singleton_Duo_Suo* instance;
    Singleton_Duo_Suo() { this_thread::sleep_for(chrono::milliseconds(500)); }
public:
    static Singleton_Duo_Suo* getInstance()
    {
        mut.lock();//加锁
        if (instance==nullptr)
        {
            instance = new Singleton_Duo_Suo();
        }
        mut.unlock();//解锁
        return instance;
    }
};
Singleton_Duo_Suo* Singleton_Duo_Suo::instance = nullptr;
//加锁后的懒汉式,多线程绑定的函数
void threadFunc_suo()
{
    Singleton_Duo_Suo* ins = Singleton_Duo_Suo::getInstance();
    cout << this_thread::get_id() << ":" << ins << endl;
}
void test05()
{
    thread t3[3];
    for (int i = 0; i < 3; i++)
    {
        t3[i] = thread(threadFunc_suo);
    }
    for (int i = 0; i < 3; i++)
    {
        t3[i].join();
    }
}

7.单例释放问题

一般单例模式不用考虑内存释放问题,因为单个对象占用的空间不大。如果手动释放,会影响调用这个对象的资源,并且bug很难找。

如果非要手动释放,可以用这两种方式实现:

1)调用delete释放内存

2)单例中提供静态方法用于释放内存

8.饿汉式——局部静态变量实现单例(代码见vs)

使用局部静态变量,非常强大的方法,完全实现了单例的特性,而且代码量更少,就是把上面的第一要素的对象属性放在getInstance函数中去创建。它的作用域就是getInstance函数中。

不用担心单例销毁的问题,静态局部变量离开作用域后,不会马上被销毁,仍然驻留在内存中,只是无法被访问,当再次调用getInstance函数的时候,就能重新访问这个变量。只有当程序结束时,该变量才会被销毁,从内存中释放,此时,单例对象也被回收了。静态变量跟程序的生命周期一致。

不用担心多线程不安全问题,因为在编译器层面,本身就是支持静态局部变量的线程安全的,所以使用静态局部变量来保存单例,也是安全的。

优点:解决线程不安全问题;解决单例析构问题;代码简洁易懂。

//局部静态变量实现单例,可以保证多线程安全
class Singleton_Jubu
{
private:
    Singleton_Jubu(){}
public:
    static Singleton_Jubu* getInstance()
    {
        //定义一个局部静态变量来指向单例对象
        static Singleton_Jubu* instance_jubu = new Singleton_Jubu();
        return instance_jubu;
    }
};
void test06()
{
    Singleton_Jubu* ins_jubu = Singleton_Jubu::getInstance();
    Singleton_Jubu* ins2_jubu = Singleton_Jubu::getInstance();
    cout << ins_jubu << "=" << ins2_jubu << endl;
}

//多线程下,验证局部静态变量单例的安全性
class Singleton_Jubu_Duo
{
private:
    Singleton_Jubu_Duo() { this_thread::sleep_for(chrono::milliseconds(500)); }
public:
    static Singleton_Jubu_Duo* getInstance()
    {
        static Singleton_Jubu_Duo* instance_jubu = new Singleton_Jubu_Duo();
        return instance_jubu;
    }
};
void threadFunc_jubu()
{
    Singleton_Jubu_Duo* ins = Singleton_Jubu_Duo::getInstance();
    cout << this_thread::get_id() << ":" << ins << endl;
}
void test07()
{
    thread t3[3];
    for (int i = 0; i < 3; i++)
    {
        t3[i] = thread(threadFunc_jubu);
    }
    for (int i = 0; i < 3; i++)
    {
        t3[i].join();
    }
}

9.单例总结

优点

1. 在内存中只有一个对象,节省内存空间。

2. 避免频繁的创建销毁对象,可以提高性能。

缺点

1. 没有接口,扩展困难。

2. 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

应用场景

1. 要求生成唯一序列号的环境。

2. 在整个项目中需要一个共享访问点或共享数据。

3. 创建一个对象需要消耗的资源过多。

4. 需要定义大量的静态常量和静态方法。如math类

注意事项

在高并发多线程情况下,注意普通单例模式的线程同步问题。

3.2 工厂模式

1.概念

在开发过程中完成某个任务时,都是通过调用实例对象的方法来实现的,需要一个准备动作(实例化对象)。如果一个类在实例化对象时操作很复杂(需要读配置文件,获取参数),可以用工厂模式,让用户和类分离,不要让用户操心对象如何创建的问题。该模式用于封装和管理对象的创建,是一种创建型模式。

工厂模式有三种:

简单工厂模式:工厂根据用户参数可以生产任意产品(产品即对象),工厂只有一层,没有抽象层,产品有抽象层和具体层。

工厂方法模式:工厂增加一个抽象层,派生出具体的工厂,具体的工厂只能生产具体的某个产品,客户不需要传参,只需要使用不同的工厂就能生产对应的产品。

抽象工厂模式:工厂和产品都有抽象层和具体层,最大的改变是具体层的每个工厂,都可以生产全部的产品,这些产品根据由哪个工厂生产的划分为不同的产品族,一个工厂的产品都属于一个产品族。

2.简单工厂模式(代码见vs)

简单工厂模式也被称为静态工厂模式;消费和生产完全分开,客户端只需要知道自己需要什么产品,如何来使用产品就可以了,具体的产品生产任务由具体的工厂类来实现。工厂类根据传进来的参数生产具体的产品供消费者使用。

#include <iostream>
using namespace std;

//简单工厂
//父类,水果类,抽象类
class AbsFruit
{
public:
	virtual void showName() = 0;//纯虚函数,接口
};
//具体产品类,苹果
class Apple :public AbsFruit
{
public:
	virtual void showName() { cout << "我是苹果" << endl; }
};
//具体产品类,桃子
class Peach :public AbsFruit
{
public:
	virtual void showName() { cout << "我是桃子" << endl; }
};
//具体产品类,香蕉
class Banana :public AbsFruit
{
public:
	virtual void showName() { cout << "我是香蕉" << endl; }
};
//简单工厂类
class SimpleFactory
{
public:
	AbsFruit* createFruit(string str)//根据参数决定生产什么产品
	{
		if (str=="apple")
		{
			return new Apple();
		}
		else if (str=="peach")
		{
			return new Peach();
		}
		else if (str=="banana")
		{
			return new Banana();
		}
	}
};
void test01()
{
	SimpleFactory sf = SimpleFactory();
	AbsFruit* a=sf.createFruit("apple");
	a->showName();
	AbsFruit* b = sf.createFruit("banana");
	b->showName();
	delete a;
	delete b;
}

简单工厂模式的构成:

具体的工厂角色:Factory;在工厂中根据参数不同生产出不同的产品;

抽象的产品角色:Product;在抽象产品类中声明接口,在具体的产品类中实现;

具体的产品角色:ProductA 和ProdcutB;在具体的类中实现抽象产品类的接口,也可以实现自己的业务逻辑。

简单工厂模式的总结

优点

工厂类包含必要的逻辑判断,可以根据用户需求动态实例化相关的类。

客户端可以免除直接创建产品对象的职责,去除了与具体产品的依赖。工厂和产品的职责区分明确。

缺点

增加产品,需要修改工厂类,扩展困难,不符合开闭原则。

客户创建实例对象时需要传入参数,需要记住参数的格式,比较麻烦。

应用场景

对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。

3.工厂方法模式(也可以称为复杂工厂)(代码见vs)

简单工厂方法违背了对扩展开放的原则,添加产品需要修改工厂类,并且高度依赖用户输入的参数。工厂方法模式是在简单工厂模式的基础上,工厂添加了一个抽象层。将工厂共同的动作抽象出来,作为抽象类,而具体的行为由子类去实现,让子类去决定生产什么样的产品。

//工厂方法模式
//抽象层工厂
class AbsFactory
{
public:
	virtual AbsFruit* createFruit() = 0;
};
//苹果工厂
class AppleFactory :public AbsFactory
{
public:
	virtual AbsFruit* createFruit() { return new Apple(); }
};
//桃子工厂
class PeachFactory :public AbsFactory
{
public:
	virtual AbsFruit* createFruit() { return new Peach(); }
};
//香蕉工厂
class BananaFactory :public AbsFactory
{
public:
	virtual AbsFruit* createFruit() { return new Banana(); }
};
void test02()
{
	//想要什么产品,就需要什么工厂
	AbsFactory* apple_fac = new AppleFactory();//创建一个苹果工厂
	AbsFruit* apple=apple_fac->createFruit();//生产苹果
	apple->showName();
	AbsFactory* banana_fac = new BananaFactory();
	AbsFruit* banana = banana_fac->createFruit();
	banana->showName();
	delete apple_fac;
	delete banana_fac;
	delete apple;
	delete banana;
}

工厂方法模式总结

工厂方法模式 = 简单工厂模式 + 开闭原则

优点

继承了简单工厂模式的优点。

系统的可扩展性变得更好,符合开闭原则。

降低了用户的使用难度,不用考虑简单工厂的传参问题。

缺点

系统中的类是成对增加,增加了系统的复杂度和理解度。

应用场景

在设计的初期,就考虑到产品在后期会进行扩展的情况下,可以使用工厂方法模式。

4.抽象工厂模式(代码见vs)

//抽象工厂
//抽象苹果
class AbsApple
{
public:
	virtual void showName() = 0;//纯虚函数,接口
};
//中国苹果
class ChinaApple :public AbsApple
{
public:
	virtual void showName() { cout << "中国苹果" << endl; }
};
//日本苹果
class JapApple :public AbsApple
{
public:
	virtual void showName() { cout << "日本苹果" << endl; }
};
//抽象桃子
class AbsPeach
{
public:
	virtual void showName() = 0;//纯虚函数,接口
};
//中国桃子
class ChinaPeach :public AbsPeach
{
public:
	virtual void showName() { cout << "中国桃子" << endl; }
};
//日本桃子
class JapPeach :public AbsPeach
{
public:
	virtual void showName() { cout << "日本桃子" << endl; }
};
//抽象工厂
class AbsFactory_Abs
{
public:
	virtual AbsApple* createApple() = 0;
	virtual AbsPeach* createPeach() = 0;
};
//中国工厂
class ChinaFactory :public AbsFactory_Abs
{
	virtual AbsApple* createApple() { return new ChinaApple(); }
	virtual AbsPeach* createPeach() { return new ChinaPeach(); }
};
//日本工厂
class JapFacotry :public AbsFactory_Abs
{
	virtual AbsApple* createApple() { return new JapApple(); }
	virtual AbsPeach* createPeach() { return new JapPeach(); }
};
void test03()
{
	//抽象工厂,每个工厂都能生产所有的产品
	AbsFactory_Abs* chinaFac = new ChinaFactory();//中国工厂
	AbsApple* china_apple = chinaFac->createApple();//生产中国苹果
	AbsPeach* china_peach = chinaFac->createPeach();//生产中国桃子
	china_apple->showName();//使用产品
	china_peach->showName();//使用产品
	delete chinaFac;
	delete china_apple;
	delete china_peach;

	AbsFactory_Abs* japFac = new JapFacotry();//日本工厂
	AbsApple* jap_apple = japFac->createApple();//生产日本苹果
	AbsPeach* jap_peach = japFac->createPeach();//生产日本桃子
	jap_apple->showName();//使用产品
	jap_peach->showName();//使用产品
	delete japFac;
	delete jap_apple;
	delete jap_peach;
}

抽象工厂总结

优点

1、抽象工厂模式隔离了具体产品的生产,使得客户并不需要知道什么产品被创建,一个工厂可以创建各种产品。

2、当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。可以理解为系统给用户提供了很多套相似的产品,每一套产品属于一个产品族,大体功能类似,但有一些细微的差别,比如同样的软件功能,但由于不同国家地区的法律法规和风俗不同,需要做出调整。

3、增加新的工厂族和产品族很方便,只需要添加新的工厂族即可,无须修改已有系统,符合“开闭原则”。

缺点

增加新的产品等级很复杂,比如增加一个橘子产品,需要修改抽象工厂和所有的具体工厂类,违反了开闭原则。

应用场景

适用于产品种类多的场合,主要用于创建一组相关的产品(属于同一个产品族),为它们提供创建的接口。注意事项:产品族易扩展,产品等级难扩展。

5.工厂模式总结

简单工厂模式:

产品有抽象层和具体层,工厂没有抽象层。工厂用来生产同一等级结构中的具体任意产品。对于增加新的产品,就要修改工厂类(需要根据参数决定生产什么产品)。符合单一职责原则。不符合开闭原则。客户传参麻烦。

工厂方法模式:

产品有抽象层和具体层,工厂也有抽象层和具体层,具体工厂用来生产固定产品。支持增加任意产品,但是增加一个产品就要增加一对(产品类和工厂类)。新增产品时不需要更改已有的工厂。符合单一职责原则、符合开闭原则。但是引入了复杂性。

抽象工厂模式 :

工厂和产品都有抽象层,工厂可以生产各种产品,不仅仅是固定的产品,这些产品都来自于同一个产品族。增加工厂族很容易,产品族容易扩展。但是增加新产品很难,需要修改已有的各个工厂族以及抽象工厂。符合单一职责原则,部分符合开闭原则,降低了复杂性。

6.练习(工厂方法模式)

#include <iostream>

using namespace std;

//抽象鼠标类
class Mouse
{
public:
	virtual void showName() = 0;
};
//dellmouse
class DellMouse :public Mouse
{
public:
	virtual void showName() { cout << "dellMouse" << endl; }
};
//hpMouse
class HpMouse :public Mouse
{
	virtual void showName() { cout << "hpMouse" << endl; }
};
//抽象工厂
class MouseFactory
{
public:
	virtual Mouse* createdellmouse() = 0;
	
};
//dellfactory
class DellFactory :public MouseFactory
{
public:
	virtual DellMouse* createdellmouse() { return new DellMouse; }
};
//hpfactory
class HpFactory :public MouseFactory
{
public:
	virtual HpMouse* createhpmouse() { return new HpMouse; }
};

void test1()
{
	MouseFactory* dellmouse = new DellFactory();
	Mouse* dell = dellmouse->createdellmouse();
	dell->showName();
	delete dellmouse;
	delete dell;
}

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

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

相关文章

Windows JDK安装详细教程

一、关于JDK 1.1 简介 Java是一种广泛使用的计算机编程语言&#xff0c;拥有跨平台、面向对象、泛型编程的特性&#xff0c;广泛应用于企业级Web应用开发和移动应用开发。 JDK&#xff08;Java Development Kit&#xff09;是用于开发 Java 应用程序的工具包。它由以下几个主要…

Python 学习笔记(二)

类 构造方法 魔术方法 类的私有成员 继承 语法 class 类(父类1&#xff0c;父类2&#xff0c;...)&#xff1a; 类内容体 对父类的复写 注解 多态

J.U.C Review - 常见的通信工具类解析

文章目录 概述1. Semaphore2. Exchanger3. CountDownLatch4. CyclicBarrier5. Phaser 原理 & Code1. Semaphore2. Exchanger3. CountDownLatch4. CyclicBarrier5. Phaser 概述 Java 的 java.util.concurrent 包提供了许多实用的工具类&#xff0c;用于简化并发编程。这些工…

计算机网络练级第一级————认识网络

网络搁哪&#xff1f; 网络大家应该都很熟悉了&#xff0c;但网络具体是怎么构成的&#xff0c;怎么用的&#xff1f;长话短说 我认为网络就是计算机里的快递业务&#xff0c;从一台计算机中发出&#xff0c;网络接收到数据后&#xff0c;就要把这个数据安全快速完整地发到目…

【idea】设置文件模板

搜索 File and Code Templates 。 添加模板。 在任意文件目录下右键&#xff0c;new->找到添加的模板。 参考链接&#xff1a; IDEA创建模板文件_edit file templates-CSDN博客

科研绘图系列:R语言宏基因组堆积图(stacked barplot)

介绍 宏基因组堆积条形图是一种数据可视化工具,用于展示宏基因组数据中不同分类群(如微生物群落中的物种或菌株)的相对丰度。宏基因组学(Metagenomics)是一种研究环境样本中所有生物的遗传物质(DNA和RNA)的科学,不依赖于培养,可以直接从环境样本中提取DNA进行测序。 …

Windows server 2016 .net framwork 安装

解决方法: 1、windows server 2016默认是不安装.netframework3.5的,可以在添加删除程序中单独添加。但是有时候系统安装文件不在的时候,找不到安装程序就不能安装成功。 这时候单独下载dotnetfx35直接安装是安装不上的,需要用以下方法进行。 2、单独安装: 通过 NetFx3.c…

无人机之动力系统篇

无人机的动力系统是其飞行中最为核心的部分&#xff0c;它决定了无人机的飞行性能和稳定性。一个完整的无人机动力系统通常由多个关键组件组成&#xff0c;这些组件协同工作&#xff0c;为无人机提供动力。以下是对无人机动力系统的详细解析&#xff1a; 一、主要组成部分 电…

大模型训练框架LLaMAFactory覆盖预训练指令微调强化学习评估全流程

1. 项目背景 开源大模型如LLaMA&#xff0c;Qwen&#xff0c;Baichuan等主要都是使用通用数据进行训练而来&#xff0c;其对于不同下游的使用场景和垂直领域的效果有待进一步提升&#xff0c;衍生出了微调训练相关的需求&#xff0c;包含预训练&#xff08;pt&#xff09;&…

3174. 清除数字(Java)

3174. 清除数字(Java) 1.Java 的 StringBuilder 初用。 2. StringBuffer和StringBuilder方法类似&#xff0c;Buffer支持同步访问&#xff0c;线程安全&#xff0c;速度比较慢&#xff0c;所以Buffer用的少&#xff0c;Builder用的多。 class Solution {public String clearD…

C语言深度剖析--不定期更新的第二弹

好久不见&#xff0c;甚是想念。书接上回&#xff0c;继续前进&#xff01; 关键字static-最名不副实的关键字 对extern声明的小小补充 当我要对一个函数进行声明的时候可不可以像如下情况&#xff1a; extern int v_gal100;对这个变量进行了赋值&#xff0c;这是不可以的&a…

相互作用先验下的 3D 分子生成扩散模型 - IPDiff 评测

IPDiff 是一个基于蛋白质-配体相互作用先验引导的扩散模型&#xff0c;首次把配体-靶标蛋白相互作用引入到扩散模型的扩散和采样过程中&#xff0c;用于蛋白质&#xff08;口袋&#xff09;特异性的三维分子生成。 本文将对 IPDiff 实际的分子生成能力进行评测。 一、背景介绍 …

动态规划的解题思想

1. 从斐波那契数列说起 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c; &#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0, F(2) 1 F&#xff08;n&#xff09; F&…

【C++】C++ STL探索:Vector使用与背后底层逻辑

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现 在string类文章中提及了STL容器间的接口是大差不差的&#xff0c;本篇将直…

虚幻5|不同骨骼受到不同伤害|小知识(2)

1.蓝图创建一个结构&#xff0c;B_BoneDamage 结构里添加一个浮点变量&#xff0c;表示伤害倍数 2.当我们创建了一个结构&#xff0c;就需要创建一个数据表格&#xff0c;数据表格可以选择对应的结构 不同骨骼不同倍数伤害&#xff0c;骨骼要对应骨骼网格体的名称 3.把我们br…

C#继承_里氏替换原则

知识点一&#xff1a;基本概念 知识点二&#xff1a;基本实现 #region 知识点二基本实现class GameObject{}class Player : GameObject{public void PlayerAtk(){Console.WriteLine("玩家攻击");}}class Monster : GameObject{public void PlayerAtk(){Console.Writ…

NLP从零开始------文本中阶处理之序列到序列模型(完整版)

1. 序列到序列模型简介 序列到序列( sequence to sequence, seq2seq) 是指输入和输出各为一个序列(如一句话) 的任务。本节将输入序列称作源序列&#xff0c;输出序列称作目标序列。序列到序列有非常多的重要应用&#xff0c; 其中最有名的是机器翻译( machine translation), 机…

消息中间件都有哪些

RabbitMQ&#xff1a;这可是一个开源的消息代理软件&#xff0c;也叫消息中间件。它支持多种消息传递协议&#xff0c;可以轻松地在分布式系统中进行可靠的消息传递。 Kafka&#xff1a;Apache Kafka是一个分布式流处理平台&#xff0c;它主要用于处理实时数据流。Kafka的设计初…

时下改变AI的6大NLP语言模型

本文将深入研究大语言模型领域的最新进展&#xff0c;改变AI的6大NLP语言模型&#xff0c;每个模型能够引入的增强功能、以及潜在功能应用与限制。 在快速发展的人工智能&#xff08;AI&#xff09;领域&#xff0c;自然语言处理&#xff08;Natural Language Processing&#…

6.1均值滤波

目录 实验原理 示例代码 运行结果 注意事项 总结 实验代码 运行结果 实验原理 https://zhuanlan.zhihu.com/p/76188487 在OpenCV中&#xff0c;cv::blur函数用于对图像进行均值滤波&#xff08;Mean Filter&#xff09;&#xff0c;这是一种线性滤波技术&#xff0c;主…