浅谈设计模式
文章目录
一、单例模式
1.饿汉模式
2.懒汉模式
二、工厂模式
三、建造者模式
四、代理模式
设计模式是前辈们对代码开发的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。
设计模式的六大原则:
1.单一职责原则
类的职责应该单一,一个方法只做一件事。职责划分清晰,每次改动到最小单位的方法或者类
使用建议:两个完全不一样的功能不应该放在同一个类中,一个类应该是一组相关性很高的函数,数据的封装
用例:网络聊天:通信类,聊天类
2.开闭原则
对扩展开发,对修改封闭
使用建议:对软件实体改动,最好使用扩展而非修改的方式
用例:超市卖货:商品价格 不是修改原来的商品价格,而是新增促销的价格
3.里氏替换原则
不要破坏继承体系
父类可以出现的地方,子类就可以出现,而且替换为子类也不会产生错误或者异常
在继承时,务必完全重写父类的方法,尤其是父类的protected方法,子类尽量不要暴露自己的public方法供外界调用
使用建议:子类完全实现父类的方法,子类可以有自己的个性,覆盖或者实现父类的方法时,输入参数可以被放大,输出可以缩小
用例:跑步运动员类-会跑步 子类长跑运动员:会跑步且擅长长跑,子类短跑运动员:会跑步且擅长短跑
4.依赖倒置原则
面向接口编程
高层次模块不应该依赖低层次模块,两者都应该依赖其抽象,不可分割的原子逻辑就是低层模式,原子逻辑组装成的就是高层模块
模块直接按依赖通过抽象(接口)发生,具体类之间不直接依赖
使用建议:每个类都尽量有抽象类,任何类都不应该从具体类派生。尽量不要重写基类的方法,结合里氏替换原则使用
用例:奔驰类司机--只能开奔驰 司机类--给什么车就开什么车 开车的人:司机 依赖抽象
5.迪米特法则 "最少知道法则"
降低耦合
尽量减少对象间的交互,从而减小类之间的耦合。一个对象应该其他对象有最少的了解,对类的低耦合提出明确的交流
用力:老师让班长点名 老师给班长一个名单,班长完成点名勾选,返回结果,而不是班长点名,老师勾选
6.接口隔离原则
客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口
使用建议:接口设计尽量精简单一,不要对外暴露没有实际意义的接口
用例:修改密码,就提供单一的最小修改密码接口,不应该提供用户信息接口,更不要暴露数据库
一、单例模式
一个类只能创建一个对象,即单例模式,该设计模式中可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
那我们需要保证:
1)该类不能被拷贝构造,不能赋值。
2)构造函数私有
单例模式有两种实现方式:饿汉模式和懒汉模式
1.饿汉模式
a.直接定义静态对象
b.静态指针+类外初始化时new
程序启动时候就会创建一个唯一的实例对象。因为单例对象已经确定,所以比较适用于多线程环境中,多线程获取单例对象不需要加锁,可以有效避免资源竞争,提高性能。缺点就是如果单例对象构造特别耗时或者耗费资源(加载插件,加载网络资源等)比较占用内存
template<typename T>
class singleTon
{private:singleTon(){}~singleTon(){}public:singleTon(const singleTon&) = delete;singleTon& operator=(const singleTon&) = delete;static T& getInstance(){return _eton;}private:static singleTon _eton;
};singleTon singleTon::_eton;
2.懒汉模式
第一次要使用的时候创建实例对象。
a.静态指针+用到的时候初始化
b.局部静态变量
template<typename T>
class singleTon{private:singleTon(){}~singleTon(){}public:singleTon(const singleTon&) = delete;singleTon& operator=(const singleTon&) = delete;static T& getInstance(){static singleTon _eton;return _eton;}
};
二、工厂模式
工厂模式是一种创建型设计模式,在工厂模式中,创建对象时候不会对上层暴露创建逻辑,而是通过一个共同结构指向新创建的对象,以此实现创建-使用的分离
1.简单工厂模式
简单工厂模式实现由一个工厂对象通过类型决定创建出来指定产品类的实例。假设有个工厂可以生产水果,客户需要产品的时候明确告知工厂生产哪类水果,工厂需要接收用户提供的类别信息,当新增产品的时候,工厂内部去添加新产品的生产方式。
这个模式的结构和管理对象的方式十分简单,但是它的可扩展性非常差,当我们需要新增产品的时候,就需要修改工厂类新增一个类型的产品创建逻辑,违背了开闭原则。
class Fruit
{public:Fruit(){}virtual void show() = 0;
};class Apple :public Fruit
{public:Apple(){}virtual void show(){ cout<<"apple method..."<<endl;}
};class Banana :public Fruit()
{public:Banana(){}virtual void show(){cout<<"banana method ..."<<endl;}
};class FruitFactory
{public:static std::shared_ptr<Fruit> create(const std::string &name){if(name =="Apple")return std::make_shared<Apple>();else if(name =="banana")return std::make_shared<Banana>();}return std::shared_ptr<Fruit>();
}
};int main()
{std::shared_ptr<Fruit> fruit = FruitFactory::create("Apple");fruit->show();return 0;
}
2.工厂方法模式
在简单工厂模式下新增多个工厂,多个产品,每个产品对于一个工厂。假设有a,b两种产品,则开两个工厂,工厂a负责生产产品a,工厂b生产产品b,用户只知道产品的工厂名,而不知道具体的产品信息,工厂不需要再接收客户的产品类别,而只负责生产产品。
工厂方法模式每次增加一个产品时,都需要增加一个具体产品类和工厂类,这会使得系统中类的个数成倍增加,在一定程度上增加了系统的耦合度。
class Fruit
{public:Fruit(){}virtual void show() = 0;
};class Apple :public Fruit
{public:Apple(){}virtual void show(){ cout<<"apple method..."<<endl;}
};class Banana :public Fruit()
{public:Banana(){}virtual void show(){cout<<"banana method ..."<<endl;}
};class AppleFactory:public FruitFactory
{public:virtual std::shared_ptr<Fruit> create(){return std::make_shared<Apple>();}
};class BananaFactory:public FruitFactory
{public:virtual std::shared_ptr<Fruit> create(){return std::make_shared<Banana>();}
};int main()
{shared_ptr<FruitFactory> Factory<new AppleFactory>());fruit = Factory->create();fruit->show()return 0;
}
3.抽象工厂模式
工厂方法模式引入工厂等级结构,解决了简单工厂模式中工厂类职责太多的问题,但是由于工厂方法模式每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,会增加系统的开销。此时可以将一些相关的产品组成一个产品族(位于不同产品等级结构中功能相关联的产品组成的家族),由同一个工厂来生产,这就是抽象工厂模式的基本思想。
抽象工厂模式适用于生产多个工厂系列产品衍生的设计模式,增加新的产品等级结构复杂,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,违背了“开闭原则”。
//围绕一个超级工厂创建其他工厂,每个生产的工厂按照工厂模式提供对象。
//思想:将工厂抽象成两层, 抽象工厂 & 具体工厂子类,在子类中生产不同的子产品class Fruit
{public:Fruit(){}virtual void show() = 0;
};class Apple : public Fruit
{public:Apple() {}virtual void show(){std::cout << "我是⼀个苹果" << std::endl;}private:std::string _color;
};class Banana : public Fruit {public:Banana() {}virtual void show() {std::cout << "我是⼀个⾹蕉" << std::endl;}
};
class Animal {public:virtual void voice() = 0;
};
class Lamp: public Animal {public:void voice() { std::cout << "咩咩咩\n"; }
};
class Dog: public Animal {public:void voice() { std::cout << "汪汪汪\n"; }
};
class Factory {public:virtual std::shared_ptr<Fruit> getFruit(const std::string &name) = 0;virtual std::shared_ptr<Animal> getAnimal(const std::string &name) = 0;
};
class FruitFactory : public Factory {public:virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {return std::shared_ptr<Animal>();}virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {if (name == "苹果") {return std::make_shared<Apple>();}else if(name == "⾹蕉"){return std::make_shared<Banana>();}return std::shared_ptr<Fruit>();}
};class AnimalFactory : public Factory {public:virtual std::shared_ptr<Fruit> getFruit(const std::string &name) {return std::shared_ptr<Fruit>();}virtual std::shared_ptr<Animal> getAnimal(const std::string &name) {if (name == "⼩⽺") {return std::make_shared<Lamp>();}else if(name == "⼩狗") {return std::make_shared<Dog>();}return std::shared_ptr<Animal>();}
};
class FactoryProducer {public:static std::shared_ptr<Factory> getFactory(const std::string &name) {if (name == "动物") {return std::make_shared<AnimalFactory>();}else {return std::make_shared<FruitFactory>();}}
};
int main()
{std::shared_ptr<Factory> fruit_factory = FactoryProducer::getFactory("⽔果");std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("苹果");fruit->show();fruit = fruit_factory->getFruit("⾹蕉");fruit->show();std::shared_ptr<Factory> animal_factory = FactoryProducer::getFactory("动物");std::shared_ptr<Animal> animal = animal_factory->getAnimal("⼩⽺");animal->voice();animal = animal_factory->getAnimal("⼩狗");animal->voice();return 0;
}
三、建造者模式
建造者模式是一种创建型设计模式,使用多个简单的对象一步一步构建成一个复杂的对象,能够将一个复杂的对象的构建与它的表示分离,提供一种创建对象的最佳方式。主要用于解决对象的构建过于复杂的问题。
建造者模式主要基于四个核心类实现:
抽象产品类;
具体产品类;
抽象builder类:创建一个产品对象所需的各个部件的抽象接口
具体产品的builder类:实现抽象接口,构建各个部件
指挥者director类:统一组件过程,提供给调用者使用,通过指挥者来构造产品
//抽象电脑类
class Computer
{public:using ptr = std::shared_ptr<Computer>;Computer(){}void setBoard(const std::string & board) { _board = board;}void setDisplay(const std::string& display) { _display = display;}virtual void setOs() = 0;std::string toString(){std::string computer = "Computer:{\n";computer += "\tboard=" + _board + ",\n";computer += "\tdisplay=" + _display + ",\n";computer += "\tOs=" + _os + ",\n";computer += "}\n;return Computer;}protected:std::string _board;std::string _display;std::string _os;
};//具体产品类
class MacBook : public Computer {public:using ptr = std::shared_ptr<MacBook>;MacBook() {}virtual void setOs() {_os = "Max Os X12";}
};//抽象建造者类 包含创建一个产品对象各个部件的抽象接口
class Builder
{public:using ptr = std::shared_ptr<Builder>;virtual void buildBorad(const std::string &board) = 0;virtual void buildDisplay(const std::string &display)=0;virtual void buildOs()=0;virtual Computer::ptr build() = 0;
};//具体产品的具体建造者类,实现抽象接口,构建和组装各个部件
class MacBookBuilder:pubilc Builder
{public:using ptr = std::shared_ptr<MacBookBuilder>;MacBookBuilder():_computer(new MackBook()){}virtual void buildBoard(const std::string &board){_computer->setBoard(board);}virtual void buildDisplay(const std::string &display){_computer->setDisplay(display);}virtual void buildOs(){_computer->setOs();}private:Computer:: ptr _computer;
};//指挥者类 提供给调用者 通过指挥者来构造复杂产品
class Director
{public:Director(Builder * builder):_builder(builder){}void construct(const std::string &board,const std::string &display){_builder->buildBoard(board);_builder->buildDisplay(display);_builder->buildOs();}private:Builder::ptr _builder;
};int main()
{Builder * builder = new MacBookBuilder();std:: unique_ptr<Director> pd(new Director(builder));pd->construct("Inter","aoc");Computer:: ptr computer = builder->build();return 0;
}
四、代理模式
代理模式指的是代理控制对其他对象的访问,也就是代理对象控制原对象的引用。在某些情况下,一个对象不适合或者不能直接引用访问,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式结构包括:一个真正要访问的对象(目标类),一个是代理对象。
目标类和代理对象实现一个接口,先访问代理对象再通过代理对象访问目标对象。
代理模式分为:静态代理和动态代理
- 静态代理指的是,在编译时就已经确定好了代理类和被代理类的关系。也就是说,在编译时就已经 确定了代理类要代理的是哪个被代理类。
- 动态代理指的是,在运⾏时才动态⽣成代理类,并将其与被代理类绑定。这意味着,在运⾏时才能 确定代理类要代理的是哪个被代理类
以租房为例,房东将房⼦租出去,但是要租房⼦出去,需要发布招租启⽰, 带⼈看房,负责维修,这 些⼯作中有些操作并⾮房东能完成,因此房东为了图省事,将房⼦委托给中介进⾏租赁
class RentHouse
{public:virtual void rentHouse() = 0;
};//房东类
class LandLord: public RentHouse
{public:void rentHouse(){cout<<"rent.."<<endl;}
};//中介 对租房功能进行加强,实现租房外的其他功能
class Intermediary :public RentHouse
{public :void rentHouse(){//发广告//带人看房_landlord.rentHouse();//后续维修}private:Landlord _landlord;
};int main()
{Intermdiary inter;inter.rentHouse();
}
相关文章:
浅谈设计模式
文章目录 一、单例模式 1.饿汉模式 2.懒汉模式 二、工厂模式 三、建造者模式 四、代理模式 设计模式是前辈们对代码开发的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解…...

企业年会/年终活动如何邀请媒体记者报道?
媒体邀约是企业或组织进行宣传的重要手段之一。通过邀请媒体参加活动,可以增加活动的曝光度和知名度,吸引更多的关注和参与。同时,媒体报道还可以提高企业或组织的权威性和可信度,从而让公众更容易接受其传达的信息。 企业年会或…...
C语言如何执行HTTP GET请求
在现代互联网时代,网络数据的获取和分析变得越来越重要。无论是为了研究市场趋势,还是为了收集信息进行数据分析,编写一个网络爬虫可以帮助我们自动化这一过程。在这篇文章中,我们将使用C语言和libcurl库来编写一个简单的网络爬虫…...
.Net 6 Nacos日志控制台疯狂发输出+Log4Net日志过滤
我们的项目配置了Log4Net 作为日志输出工具,在引入Nacos后,控制台和日志里疯狂输出nacos心跳日志和其他相关信息,导致自己记录的信息被淹没了,找了很多解决办法: 1、提高nacos日志级别,然后再屏蔽相应级别…...

Libra R-CNN: Towards Balanced Learning for Object Detection(2019.4)
文章目录 AbstractIntroduction引入问题1) Sample level imbalance2) Feature level imbalance3) Objective level imbalance进行解决贡献 Related Work(他人的work,捎带与我们的对比)Model architectures for object detection&a…...

Redis的内存淘汰策略分析
概念 LRU 是按访问时间排序,发生淘汰的时候,把访问时间最久的淘汰掉。LFU 是按频次排序,一个数据被访问过,把它的频次 1,发生淘汰的时候,把频次低的淘汰掉。 几种LRU策略 以下集中LRU测率网上有很多&am…...

git命令之遭遇 ignore罕见问题解决
我先来讲讲背景 我的一些文件在ignore了,不会被提交到远程仓库,这时候我的远程仓库中是没有这几个文件的,这时候我如果使用 git reset 的话这时候除了那几个 ignore 的文件以外都被更新的,但是如果我不需要这几个被 ignore 的文件…...
torch DDP多卡训练教程记录
参考 简明教程看这里 --> pytorch分布式训练 和这篇: [PyTorch]> DDP系列第一篇:入门教程 --》 详细解答了pipeline DDP原理篇 --> DDP系列第二篇:实现原理与源代码解析 --》 主要讲 all_reduce 和 sample 的实现 减少GPU占用看这里…...

Jenkins CICD过程常见异常
1 Status [126] Exception when publishing, exception message [Exec exit status not zero. Status [126] 1.1 报错日志 SSH: EXEC: STDOUT/STDERR from command [/app/***/publish.sh] ... bash: /app/***/publish.sh: Permission denied SSH: EXEC: completed after 200…...

Java11新增特性
前言 在前面的文章中,我们已经介绍了 Java9的新增特性 和 Java10的新增特性 ,下面我们书接上文,来介绍一下Java11的新增特性 版本简介 Java 11 是 Java 平台的最新版本,于2018年9月25日发布。这个版本是自Java 8以来最重要的更新之一&…...
安卓常见设计模式13------过滤器模式(Kotlin版)
W1 是什么,什么是过滤器模式? 过滤器模式(Filter Pattern)是一种常用的结构型设计模式,用于根据特定条件过滤和筛选数据。 2. W2 为什么,为什么需要使用过滤器模式,能给我们编码带来什么好处…...
使用spark进行递归的可行方案
在实际工作中会遇到,最近有需求将产品炸开bom到底层,但是ERP中bom数据在一张表中递归存储的,不循环展开,是无法知道最底层原材料是什么。 在ERP中使用pl/sql甚至sql是可以进行炸BOM的,但是怎么使用spark展开࿰…...

Spring -Spring之依赖注入源码解析(下)--实践(流程图)
IOC依赖注入流程图 注入的顺序及优先级:type-->Qualifier-->Primary-->PriOriry-->name...
前端设计模式之【单例模式】
文章目录 前言介绍实现单例模式优缺点?后言 前言 hello world欢迎来到前端的新世界 😜当前文章系列专栏:前端设计模式 🐱👓博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果出…...

设备零部件更换ar远程指导系统加强培训效果
随着科技的发展,AR技术已经成为了一种广泛应用的新型技术。AR远程指导系统作为AR技术的一种应用,具有非常广泛的应用前景。 一、应用场景 气象监测AR教学软件适用于多个领域,包括气象、环境、地理等。在教学过程中,软件可以帮助学…...

文本生成高精准3D模型,北京智源AI研究院等出品—3D-GPT
北京智源AI研究院、牛津大学、澳大利亚国立大学联合发布了一项研究—3D-GPT,通过文本问答方式就能创建高精准3D模型。 据悉,3D-GPT使用了大语言模型的多任务推理能力,通过任务调度代理、概念化代理和建模代理三大模块,简化了3D建模的开发流程…...

Netty入门指南之NIO 网络编程
作者简介:☕️大家好,我是Aomsir,一个爱折腾的开发者! 个人主页:Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏:Netty应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言基础扫…...

LeetCode(6)轮转数组【数组/字符串】【中等】
目录 1.题目2.答案3.提交结果截图 链接: 189. 轮转数组 1.题目 给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1…...

华为云Ascend310服务器使用
使用华为云服务器 cpu: 16vCPUs Kunpeng 920 内存:16GiB gpu:4* HUAWEI Ascend 310 cann: 20.1.rc1 操作系统:Ubuntu aarch64目的 使用该服务器进行docker镜像编译,测试模型。 已知生产环境:mindx版本为3.0.rc3&a…...

【poi导出excel模板——通过建造者模式+策略模式+函数式接口实现】
poi导出excel模板——通过建造者模式策略模式函数式接口实现 poi导出excel示例优化思路代码实现补充建造者模式策略模式 poi导出excel示例 首先我们现看一下poi如何导出excel,这里举个例子:目前想要导出一个Map<sex,List>信息,sex作为…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...