【设计模式】我对设计模式的C语言解读(下)

news2024/7/4 5:51:28

书接上回

由于内容太多,编辑器太卡了,所以分P了
上P在这里

目录

  • 书接上回
    • 备忘录模式
    • 观察者模式

备忘录模式

备忘录模式的介绍: https://refactoringguru.cn/design-patterns/memento
备忘录模式的C++实现: https://refactoringguru.cn/design-patterns/memento/cpp/example
这个模式还是挺复杂的
大概的套路就是这样
原发者自己有保存状态和恢复状态的接口
负责人做一个统筹,它有一个指针指向待处理的原发者
它自己的备份和恢复接口内部就调用原发者提供的接口,保存原发者状态到备忘录或者恢复备忘录到原发者(通过创建备忘录类)
在这里插入图片描述
C++的代码相对还是好理解的,如果换C语言来写,还是比较复杂的,涉及到动态内存,模拟String功能
我通过dyad库的动态模板数据类型,做了一个简单的string库

#include <iostream>
#include <string>
#include <vector>
#pragma warning(disable:4996)

//这里借用了dyad[一个单文件的C语言实现的简单的TCP库]中动态数组的实现方法
//借用宏的方式实现了类似C++中模板的感觉

//dyad动态数组

//内存部分

//动态申请
static void* dyad_realloc(void* ptr, int n)
{
	ptr = realloc(ptr, n);
	if ((!ptr) && (n != 0))
	{
		printf("out of mem!!\r\n");
		exit(-1);
	}
	return ptr;
}

//动态释放
static void dyad_free(void* ptr)
{
	free(ptr);
}

//动态数组

#define Vec(T)\
  struct { T *data; int length, capacity; }

#define vec_unpack(v)\
(char**)&(v)->data, &(v)->length, &(v)->capacity, sizeof(*(v)->data)

#define vec_init(v)\
  memset((v), 0, sizeof(*(v)))

#define vec_deinit(v)\
  dyad_free((v)->data)

#define vec_clear(v)\
  ((v)->length = 0)

#define vec_push(v, val)\
  ( vec_expand(vec_unpack(v)),\
    (v)->data[(v)->length++] = (val) )

#define vec_splice(v, start, count)\
  ( vec_splice(vec_unpack(v), start, count),\
    (v)->length -= (count) )



//扩展
static void vec_expand(char** data, int* length, int* capacity, int memsz)
{
	int before = 0;
	if (*length + 1 > *capacity)
	{
		before = *capacity;
		if (*capacity == 0)
		{
			*capacity = 1;
		}
		else
		{
			*capacity <<= 1;//容量翻倍
		}
		*data = (char*)dyad_realloc(*data, *capacity * memsz);
		//注意清空额外申请出来的内存
		memset(*data + before, 0, *capacity / 2);
	}
}



/// <summary>
/// 模拟字符串
/// </summary>
typedef struct
{
	Vec(char) _vec;
}SimString;

//字符串初始化
void SimString_Init(SimString* p, const char* str)
{
	vec_init(&p->_vec);
	for (int i = 0; i < strlen(str); i++)
	{
		vec_push(&p->_vec, str[i]);
	}
}

//获取字符串
void SimString_Get(SimString* p, char* str)
{
	for (int i = 0; i < p->_vec.length; i++)
	{
		str[i] = p->_vec.data[i];
	}
}

//截取字符串
void SimString_Splice(SimString* p, char* str,int start,int end)
{
	if (
		(start < p->_vec.length) 
		&& (end < p->_vec.length) 
		&&(start<end)
		)
	{
		int i = 0;
		for ( i= start; i < end; i++)
		{
			str[i] = p->_vec.data[i];
		}
		//添加结束符
		str[i] = '\0';
	}
}

//拼接
void SimString_Cat(SimString* p, const char* str)
{
	for (int i = 0; i < strlen(str); i++)
	{
		vec_push(&p->_vec, str[i]);
	}
}

/// <summary>
/// 打印字符串
/// </summary>
/// <param name="p"></param>
void SimString_Print(SimString* p)
{
	printf("%s\r\n",p->_vec.data);
	
}

/// <summary>
/// 输出指定长度的字符串
/// </summary>
/// <param name="p"></param>
/// <param name="len"></param>
void SimString_Show(SimString* p, int start,int end)
{
	for (int i = start; (i<p->_vec.length)&&(i < end); i++)
	{
		printf("%c", p->_vec.data[i]);
	}
	printf("\r\n");
}

/// <summary>
/// 拷贝字符串
/// </summary>
/// <param name="dst"></param>
/// <param name="src"></param>
void SimString_Copy(SimString* dst, SimString* src)
{
	vec_init(&dst->_vec);
	for (int i = 0; i < src->_vec.length; i++)
	{
		vec_push(&dst->_vec, src->_vec.data[i]);
	}
}

/



typedef SimString(*FuncPtr)(void*);
typedef struct
{
	FuncPtr GetName;
	FuncPtr date;
	FuncPtr state;
}Memento;



typedef struct
{
	Memento _memento;
	SimString state_;
	SimString date_;
}ConcreteMemento;

SimString ConcreteMemento_date(void* p);
SimString ConcreteMemento_GetName(void* p);
SimString ConcreteMemento_state(void* p);

/// <summary>
/// 初始化
/// </summary>
/// <param name="p"></param>
/// <param name="state"></param>
void ConcreteMemento_Init(ConcreteMemento* p, const char* state)
{
	SimString_Init(&p->state_, state);
	p->_memento.date = ConcreteMemento_date;
	p->_memento.state = ConcreteMemento_state;
	p->_memento.GetName = ConcreteMemento_GetName;

	time_t current_time;
	char* c_time_string;

	/* Get the current time */
	current_time = time(NULL);

	/* Convert to local time format */
	c_time_string = ctime(&current_time);
	SimString_Init(&p->date_, c_time_string);
}

/// <summary>
/// 返回状态
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
SimString ConcreteMemento_state(void*p)
{
	ConcreteMemento* pp = (ConcreteMemento*)p;
	return pp->state_;
}

/// <summary>
/// 获取名字
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
SimString ConcreteMemento_GetName(void* p)
{
	ConcreteMemento* pp = (ConcreteMemento*)p;

	SimString* ret = (SimString*)malloc(sizeof(SimString));

	
	SimString_Init(ret, pp->date_._vec.data);
	SimString_Cat(ret, "-/-(");

	char* tmp = (char*)malloc(50);
	SimString_Splice(&pp->state_, tmp, 0, 9);

	SimString_Cat(ret, tmp);

	SimString_Cat(ret, "...)");

	free(tmp);
	
	return *ret;
}

/// <summary>
/// 获取日期
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
SimString ConcreteMemento_date(void* p)
{
	ConcreteMemento* pp = (ConcreteMemento*)p;
	return pp->date_;
}

/// <summary>
/// 删除
/// </summary>
/// <param name="p"></param>
void ConcreteMemento_Dele(ConcreteMemento* p)
{
	vec_deinit(&p->date_._vec);
	vec_deinit(&p->state_._vec);
}



typedef struct
{
	SimString state_;
}Originator;

/// <summary>
/// 初始化
/// </summary>
/// <param name="p"></param>
/// <param name="state"></param>
void Originator_Init(Originator*p, const char * state)
{
	SimString_Init(&p->state_, state);
	std::cout << "被记录者: 我的初始状态是: " ;
	SimString_Print(&p->state_);
}

/// <summary>
/// 删除
/// </summary>
/// <param name="p"></param>
void Originator_Del(Originator* p)
{
	vec_deinit(&p->state_._vec);
}

/// <summary>
/// 随机字符串
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
std::string GenerateRandomString(int length) {
	const char alphanum[] =
		"0123456789"
		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		"abcdefghijklmnopqrstuvwxyz";
	int stringLength = sizeof(alphanum) - 1;

	std::string random_string;
	for (int i = 0; i < length; i++) {
		random_string += alphanum[std::rand() % stringLength];
	}
	return random_string;
}

/// <summary>
/// 做事
/// </summary>
/// <param name="p"></param>
void Originator_DoSomething(Originator* p)
{
	std::cout << "被记录者: 我希望做些重要的事情\n";
	 SimString_Init( &p->state_ ,GenerateRandomString(30).c_str());
	std::cout << "被记录者: 然后我的状态发生变化了: " ;
	SimString_Print(&p->state_);

}

/// <summary>
/// 保存
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
Memento* Originator_Save(Originator* p)
{
	char* tmp = (char*)malloc(50);
	ConcreteMemento* pp = (ConcreteMemento*)malloc(sizeof(ConcreteMemento));
	SimString_Get(&p->state_, tmp);
	ConcreteMemento_Init(pp, tmp);
	free(tmp);
	return (Memento*)(pp);
}

/// <summary>
/// 恢复
/// </summary>
/// <param name="p"></param>
/// <param name="memento"></param>
void Originator_Restore(Originator* p,Memento* memento)
{   
	ConcreteMemento* pp = (ConcreteMemento*)memento;
	SimString* tmp = (SimString*)malloc(sizeof(SimString));
	SimString_Init(tmp, "xxx");
	SimString_Copy(&pp->state_,tmp);
	std::cout << "被记录者: 我的状态发生变化了: \r\n";
	SimString_Print(&p->state_);
}


typedef struct
{
	std::vector<Memento*> mementos_;
	Originator* originator_;
}Caretaker;

/// <summary>
/// 初始化
/// </summary>
/// <param name="p"></param>
/// <param name="o"></param>
void Caretaker_Init(Caretaker* p, Originator* o)
{
	p->originator_ = o;
}

/// <summary>
/// 删除
/// </summary>
/// <param name="p"></param>
void Caretaker_Dele(Caretaker* p)
{
	for (auto m : p->mementos_) delete m;
}

/// <summary>
/// 备份
/// </summary>
/// <param name="p"></param>
void Caretaker_Backup(Caretaker* p)
{
	std::cout << "\n负责人: 正在保存当前状态...\n";
	p->mementos_.push_back(Originator_Save(p->originator_));
}

/// <summary>
/// 撤销
/// </summary>
/// <param name="p"></param>
void Caretaker_Undo(Caretaker* p) {
	if (!p->mementos_.size()) {
		return;
	}
	Memento* memento = p->mementos_.back();
	p->mementos_.pop_back();
	std::cout << "负责人: 把状态恢复到: ";
	SimString* tmp = (SimString*)malloc(sizeof(SimString));

	*tmp = (ConcreteMemento_GetName(memento));
	SimString_Print(tmp);
	Originator_Restore(p->originator_,memento);
	free(tmp);
}

/// <summary>
/// 显示历史
/// </summary>
/// <param name="p"></param>
void Caretaker_ShowHistory(Caretaker* p)
{
	std::cout << "负责人: 这是目前的记录:\n";
	for (Memento* memento : p->mementos_) {
		SimString* tmp = (SimString*)malloc(sizeof(SimString));
		* tmp = (ConcreteMemento_GetName(memento));
		SimString_Print(tmp);
		free(tmp);
	}
}

void mementoC()
{
	Originator originator;
	Caretaker caretaker;
	Originator_Init(&originator, "Super-duper-super-puper-super.");
	Caretaker_Init(&caretaker, &originator);

	Caretaker_Backup(&caretaker);
	Originator_DoSomething(&originator);

	Caretaker_Backup(&caretaker);
	Originator_DoSomething(&originator);

	Caretaker_Backup(&caretaker);
	Originator_DoSomething(&originator);

	Caretaker_ShowHistory(&caretaker);

	std::cout << "\n客户端: 现在开始回滚!\n\n";
	Caretaker_Undo(&caretaker);

	std::cout << "\n客户端: 现在开始回滚!\n\n";
	Caretaker_Undo(&caretaker);

	Originator_Del(&originator);
	Caretaker_Dele(&caretaker);

}

运行结果:
在这里插入图片描述

观察者模式

观察者模式的介绍: https://refactoringguru.cn/design-patterns/observer
观察者模式的C++实现: https://refactoringguru.cn/design-patterns/observer/cpp/example
这个观察者模式也是挺复杂的
就是观察者内部存在一个指针(C++里是一个引用),这个指针记录着需要观察的对象
被观察者在执行“通知”操作后,会“通知”到所有的观察者
如果不希望观察了,观察者提供一个接口,可以移除需要被观察的对象,移除被观察者中记录观察者表对象信息的记录。
观察者都持有同样的“更新”接口,被观察者拥有同样的“附加”,“移除”,“通知”接口
C++实现还是相对清晰的,C实现就会比较绕,没有引用和This指针就得换其他的方式模式出来
上代码:

#include <iostream>
#include <list>
#include <string>

//dyad动态数组

//内存部分

//动态申请
static void* dyad_realloc(void* ptr, int n)
{
	ptr = realloc(ptr, n);
	if ((!ptr) && (n != 0))
	{
		printf("out of mem!!\r\n");
		exit(-1);
	}
	return ptr;
}

//动态释放
static void dyad_free(void* ptr)
{
	free(ptr);
}

//动态数组

#define Vec(T)\
  struct { T *data; int length, capacity; }

#define vec_unpack(v)\
(char**)&(v)->data, &(v)->length, &(v)->capacity, sizeof(*(v)->data)

#define vec_init(v)\
  memset((v), 0, sizeof(*(v)))

#define vec_deinit(v)\
  dyad_free((v)->data)

#define vec_clear(v)\
  ((v)->length = 0)

#define vec_push(v, val)\
  ( vec_expand(vec_unpack(v)),\
    (v)->data[(v)->length++] = (val) )

#define vec_splice(v, start, count)\
  ( vec_splice(vec_unpack(v), start, count),\
    (v)->length -= (count) )



//扩展
static void vec_expand(char** data, int* length, int* capacity, int memsz)
{
	int before = 0;
	if (*length + 1 > *capacity)
	{
		before = *capacity;
		if (*capacity == 0)
		{
			*capacity = 1;
		}
		else
		{
			*capacity <<= 1;//容量翻倍
		}
		*data = (char*)dyad_realloc(*data, *capacity * memsz);
		//注意清空额外申请出来的内存
		memset(*data + before, 0, *capacity / 2);
	}
}



/// <summary>
/// 模拟字符串
/// </summary>
typedef struct
{
	Vec(char) _vec;
}SimString;

//字符串初始化
static void SimString_Init(SimString* p, const char* str)
{
	vec_init(&p->_vec);
	for (int i = 0; i < strlen(str); i++)
	{
		vec_push(&p->_vec, str[i]);
	}
}

//获取字符串
static void SimString_Get(SimString* p, char* str)
{
	for (int i = 0; i < p->_vec.length; i++)
	{
		str[i] = p->_vec.data[i];
	}
}

//截取字符串
static void SimString_Splice(SimString* p, char* str, int start, int end)
{
	if (
		(start < p->_vec.length)
		&& (end < p->_vec.length)
		&& (start < end)
		)
	{
		int i = 0;
		for (i = start; i < end; i++)
		{
			str[i] = p->_vec.data[i];
		}
		//添加结束符
		str[i] = '\0';
	}
}

//拼接
static void SimString_Cat(SimString* p, const char* str)
{
	for (int i = 0; i < strlen(str); i++)
	{
		vec_push(&p->_vec, str[i]);
	}
}

/// <summary>
/// 打印字符串
/// </summary>
/// <param name="p"></param>
static void SimString_Print(SimString* p)
{
	printf("%s\r\n", p->_vec.data);

}

/// <summary>
/// 输出指定长度的字符串
/// </summary>
/// <param name="p"></param>
/// <param name="len"></param>
static void SimString_Show(SimString* p, int start, int end)
{
	for (int i = start; (i < p->_vec.length) && (i < end); i++)
	{
		printf("%c", p->_vec.data[i]);
	}
	printf("\r\n");
}

/// <summary>
/// 拷贝字符串
/// </summary>
/// <param name="dst"></param>
/// <param name="src"></param>
static void SimString_Copy(SimString* dst, SimString* src)
{
	vec_init(&dst->_vec);
	for (int i = 0; i < src->_vec.length; i++)
	{
		vec_push(&dst->_vec, src->_vec.data[i]);
	}
}

/

typedef void(*Update)(void * p,SimString mess);
typedef struct
{
	Update _update;
}IObserver;


typedef void (*Attach)(void* p, IObserver* observer);
typedef void (*Detach)(void* p, IObserver* observer);
typedef void (*Notify)(void* p);
typedef struct
{
	Attach _attach;
	Detach _detach;
	Notify _notify;
}ISubject;

typedef struct
{
	ISubject _isubject;
	std::list<IObserver*> list_observer_;
	SimString message_;
}Subject;


void Subject_Attach(void* p, IObserver* observer);
void Subject_Detach(void* p, IObserver* observer);
void Subject_Notify(void* p);


void Subject_Init(Subject* p)
{
	p->_isubject._attach = Subject_Attach;
	p->_isubject._detach = Subject_Detach;
	p->_isubject._notify = Subject_Notify;
	SimString_Init(&p->message_,"xxx");
}
void Subject_DeInit(Subject* p)
{
	std::cout << "Goodbye, I was the Subject.\n";
}

void Subject_Attach(void* p, IObserver* observer)
{
	Subject* pp = (Subject*)p;
	pp->list_observer_.push_back(observer);
}

void Subject_Detach(void* p, IObserver* observer)
{
	Subject* pp = (Subject*)p;
	pp->list_observer_.remove(observer);
}

void HowManyObserver(Subject *s) {
	std::cout << "There are " << s->list_observer_.size() << " observers in the list.\n";
}

void Subject_Notify(void* p)
{
	Subject* pp = (Subject*)p;
	//通知所有观察者
	std::list<IObserver*>::iterator iterator = pp->list_observer_.begin();
	HowManyObserver(pp);
	while (iterator != pp->list_observer_.end()) {
		(*iterator)->_update((*iterator), pp->message_);
		++iterator;
	}
}

void Subject_CreateMessage(Subject* s,const char * mes)
{
	SimString_Init(&s->message_, mes);
	Subject_Notify(s);
}

void SomeBusinessLogic(Subject* s) {
	SimString_Init(&s->message_, "change message message");
	s->_isubject._notify(s);
	std::cout << "I'm about to do some thing important\n";
}


typedef struct
{
	IObserver _iobserver;
	SimString message_from_subject_;
	Subject * subject_;
	int static_number_;
	int number_;
}Observer;

void Observer_Update(void* p, SimString mess);
static int num = 0;
void Observer_Init(Observer *p,Subject*s)
{

	num++;
	p->_iobserver._update = Observer_Update;
	p->subject_ = s;
	p->subject_->_isubject._attach = Subject_Attach;
	p->subject_->_isubject._detach = Subject_Detach;
	p->subject_->_isubject._notify = Subject_Notify;

	p->subject_->list_observer_ = s->list_observer_;

	SimString_Copy(&p->subject_->message_, &s->message_);
	p->subject_->_isubject._attach = s->_isubject._attach;
	p->subject_->_isubject._detach = s->_isubject._detach;
	p->subject_->_isubject._notify = s->_isubject._notify;

	p->subject_->_isubject._attach(s, &p->_iobserver);


	p->number_ = num;
	p->static_number_ = num;

	std::cout << "Hi, I'm the Observer \"" <<
		p->static_number_ << "\".\n";
}

void Observer_DeInit(Observer* p)
{
	std::cout << "Goodbye, I was the Observer \"" << p->number_ << "\".\n";
}

void PrintInfo(Observer* p) {
	std::cout << "Observer \""
		<< p->number_ << "\": a new message is available --> ";
	SimString_Print(&p->message_from_subject_);
	
}
void Observer_Update(void* p, SimString mess)
{
	Observer* pp = (Observer*)p;
	SimString_Init(&pp->message_from_subject_, mess._vec.data);
	PrintInfo(pp);
}

void Observer_RemoveMeFromTheList(Observer* p) {
	p->subject_->_isubject._detach(p->subject_,&p->_iobserver);
	std::cout << "Observer \"" << p->number_ 
		<< "\" removed from the list.\n";
}


static void ClientCode()
{
	Subject subject;
	Subject_Init(&subject);

	Observer ob1,ob2,ob3,ob4,ob5;
	Observer_Init(&ob1,&subject);
	Observer_Init(&ob2, &subject);
	Observer_Init(&ob3, &subject);

	Subject_CreateMessage(&subject, "Hello World! :D");
	Observer_RemoveMeFromTheList(&ob3);

	Subject_CreateMessage(&subject, "The weather is hot today! :p");
	Observer_Init(&ob4, &subject);

	Observer_RemoveMeFromTheList(&ob2);
	Observer_Init(&ob5, &subject);

	Subject_CreateMessage(&subject, "My new car is great! ;)");
	Observer_RemoveMeFromTheList(&ob5);

	Observer_RemoveMeFromTheList(&ob4);
	Observer_RemoveMeFromTheList(&ob1);

	Observer_DeInit(&ob1);
	Observer_DeInit(&ob2);
	Observer_DeInit(&ob3);
	Observer_DeInit(&ob4);
	Observer_DeInit(&ob5);

	Subject_DeInit(&subject);
}

void ObserverC() {
	ClientCode();
}

在这里插入图片描述

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

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

相关文章

【数据挖掘与商务智能决策】第十三章 数据降维之PCA 主成分分析

13.1.2 PCA主成分分析代码实现 1.二维空间降维Python代码实现 import numpy as np X np.array([[1, 1], [2, 2], [3, 3]]) Xarray([[1, 1],[2, 2],[3, 3]])# 也可以通过pandas库来构造数据&#xff0c;效果一样 import pandas as pd X pd.DataFrame([[1, 1], [2, 2], [3, 3…

二分查找【数组】

⭐前言⭐ ※※※大家好&#xff01;我是同学〖森〗&#xff0c;一名计算机爱好者&#xff0c;今天让我们进入复习模式。若有错误&#xff0c;请多多指教。更多有趣的代码请移步Gitee &#x1f44d; 点赞 ⭐ 收藏 &#x1f4dd;留言 都是我创作的最大的动力&#xff01; 题目 70…

接口测试用例设计思路

&#xff08;我的公众号“墨石测试攻略”&#xff0c;关注获取软件测试相关知识及整套接口测试实战项目&#xff01;&#xff09; 接口测试用例的设计&#xff0c;从功能测试角度来说&#xff1a;首先需要分析接口文档。 现在很多公司都使用swagger来管理接口。swagger中可以…

fMRI时间序列振幅和相位对功能连接分析的影响

导读 目的&#xff1a;fMRI领域的一些研究使用瞬时相位(IP)表征(源自BOLD时间序列的解析表征)考察了脑区之间的同步性。本研究假设来自不同脑区的瞬时振幅(IA)表征可以为脑功能网络提供额外的信息。为此&#xff0c;本研究探索了静息态BOLD fMRI信号的这种表征&#xff0c;用于…

SpringBoot AnnotationFormatterFactory接口+自定义注解实现类型转换

参考资料 自定义AnnotationFormatterFactory实现注解方式类型转换Spring MVC 基于AnnotationFormatterFactory接口实现自定义的规则 目录 一. 前期准备1.1. 自定义转换标记注解1.2 入参form 二. 实现AnnotationFormatterFactory接口&#xff0c;构建格式化Factory2.1 code补全…

【7】一篇文章学习 Linux 中一些硬核的常用知识

目录 一、systemctl二、软链接三、日期&#xff08;date 命令&#xff09;四、Linux 的时区(1) 修改时区(2) ntp 五、IP 地址六、主机名七、域名解析八、配置 Linux 的固定 IP 地址(1) 在 VMwareWorkstation 中配置 IP 地址网关和网段&#xff08;IP 地址的范围&#xff09;(2)…

[陇剑杯 2021]之Misc篇(NSSCTF)刷题记录④

NSSCTF-Misc篇-[陇剑杯 2021] jwt&#xff1a;[陇剑杯 2021]jwt&#xff08;问1&#xff09;[陇剑杯 2021]jwt&#xff08;问2&#xff09;[陇剑杯 2021]jwt&#xff08;问3&#xff09;[陇剑杯 2021]jwt&#xff08;问4&#xff09;[陇剑杯 2021]jwt&#xff08;问5&#xff0…

洗地性价比高的是哪款?性价比高的洗地机推荐

在如今人工智能随处可见的时代&#xff0c;洗地机已经成为了我们家庭清洁的得力助手&#xff0c;它用高效便捷的清洁方式&#xff0c;对于地面的灰尘或者地板之间的缝隙里的细小垃圾&#xff0c;能够快速清理&#xff0c;省时省力。然而&#xff0c;对于很多消费者来说&#xf…

一文带你学会如何写一份糟糕透顶的简历

我们每个人几乎都会面对找工作这件事&#xff0c;而找工作或者说求职首先就是要写一份简历。今天狗哥将以一个不同的视角带你写一份无与伦比&#xff0c;糟糕透顶的求职简历&#xff0c;说实话&#xff0c;其实几年前&#xff0c;我就是这么写的。 目录 1. 文件名 2. 基本信…

AttributeError: ‘ChatGLMModel‘ object has no attribute ‘prefix_encoder‘

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

基于蛋白-配体复合物药效团药物设计(Pharmacophore)

基于蛋白-配体复合物药效团药物设计&#xff08;Pharmacophore&#xff09; step 1.蛋白-配体复合物准备 点击File-->Import Structures导入之前已经下载好的1IEP.pdb&#xff08;Abl蛋白和Imatinib的晶体复合物&#xff09; 蛋白准备&#xff1a;点击Tasks--->Protei…

18、越狱

一、越狱 1.1 越狱 通过iOS系统安全启动链漏洞,从而禁止掉信任链中负责验证的组件.拿到iOS系统最大权限Root权限 1.2 iOS系统安全启动链 当启动一台iOS设备时,系统首先会从只读的ROM中读取初始化指令,也就是系统的引导程序(事实上所有的操作系统启动时都要经过这一步,只是过程…

Pytorch深度学习笔记(十一)卷积神经网络CNN

目录 1.概述 2.单通道卷积 3.多通道卷积 4.卷积层常见的参数 5.代码实现&#xff08;卷积神经网络训练MNIST数据集&#xff09; 推荐课程&#xff1a;10.卷积神经网络&#xff08;基础篇&#xff09;_哔哩哔哩_bilibili 1.概述 全连接神经网络&#xff1a;完全由线性层串…

最佳实践|如何写出简单高效的 Flink SQL?

摘要&#xff1a;本文整理自阿里巴巴高级技术专家、Apache Flink PMC 贺小令&#xff0c;在 Flink Forward Asia 2022 生产实践专场的分享。本篇内容主要分为三个部分&#xff1a; 1. Flink SQL Insight 2. Best Practices 3. Future Works Tips&#xff1a;点击「阅读原文」查…

android之 Launcher改造仿桌面排版的效果

一&#xff0c;背景 1.1 新接手一个灯光控制项目&#xff0c;其页面和效果还是比交复杂的&#xff0c;其中一个功能就是仿苹果桌面来排版灯具&#xff0c;支持拖拽&#xff0c;分组&#xff0c;分页。 拖动图标的时候判断是否空白位置还是已经有占位了&#xff0c;有的话就把…

pikachu靶场-RCE

RCE漏洞概述 可以让攻击者直接向后台服务器远程注入操作系统命令或者代码&#xff0c;从而控制后台系统。 远程系统命令执行 命令执行漏洞&#xff08;Command Execution&#xff09;即黑客可以直接在Web应用中执行系统命令&#xff0c;从而获取敏感信息或者拿下shell权限 更…

Linux离线状态下安装cuda、cudnn、cudatoolkit

目录 1. 下载与安装说明2. CUDA安装3. cuDNN安装4. cudatoolkit安装5. 测试安装成功 1. 下载与安装说明 工具包下载地址 CUDA历史版本下载地址&#xff1a;https://developer.nvidia.com/cuda-toolkit-archivecuDNN历史版本下载地址&#xff1a;https://developer.nvidia.com/r…

logback日志框架集成方式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、logback是什么&#xff1f;二、使用步骤1.使用方式控制台输出配置文件输出配置html输出配置定期删除配置方式 总结 前言 提示&#xff1a;这里可以添加本文…

C++每日一练:最长递增区间 阿波罗的魔力宝石 投篮

文章目录 前言一、最长递增区间二、阿波罗的魔力宝石三、投篮总结 前言 今天的题太简单&#xff0c;甚至 “最长递增区间” 和 “投篮” 就是一个问题。实在没事干&#xff0c;也给做了&#xff01;直接上代码算了… 提示&#xff1a;以下是本篇文章正文内容 一、最长递增区间…

LSSANet:一种用于肺结节检测的长、短切片感知网络

文章目录 LSSANet: A Long Short Slice-Aware Network for Pulmonary Nodule Detection摘要方法Long Short Slice GroupingLong Short Slice-Aware Network 实验结果 LSSANet: A Long Short Slice-Aware Network for Pulmonary Nodule Detection 摘要 提出了一个长短片感知网…