设计模式(一)-设计原则(1)
六大设计原则
1、单一职责原则
特点: 类和方法属性等,都应当遵守单一职责。尽可能保持统一性,单一性。
含义:
(1)统一性,定义一个模块就必须要符合所有对象的行为特征。比如声明一个 Animal 类,有飞、呼吸等行为。而如果实例化一个动物鱼,则鱼不符合飞的行为特征,也就不满足统一性。
(2)单一性。只做一种事情。比如声明一个文件下载上传的类。在类里面,不仅要实现文件的下载上传,还对文件进行读写的功能等。该类在这过程中做了多件不同的事情,不符合单一职责原则。
优点: 高内聚,修改当前模块对其他模块的影响很低。
缺点: 过度单一,过度细分,就会增加系统的复杂程度。
反例:
public class Files{ // 违反单一性:该类处理三种不同的逻辑,分别为接受发送文件、读写文件、连接网络。//1.负责接受发送文件public void ReveFile() { }public void SendFile() { }//2.负责读写文件public void Write(){}public void Read(){}// 不具有统一性,如果是 PDF 文件,则不能通过 TXT 记事本来打开。public void OpenToTxt(string file) { }//3:处理网络的连接public void SocketFor(string socketType) {//在此方法内,实现了多种不同的逻辑,同样不符合单一职责原则/*//1).sokcet 绑定Socket.Binding();...//2). 检测网络问题if (CheckNet.IsNet) setNet else Failed Link.. //3).更新页面上的网络状态Task.Run(=> NetState.Refresh...)...*/}}
正例:
//单一职责:通过 soket 来接受发送文件public class HttpsFile{Sockets socket;public void Reve() { }public void Send() { }}//单一职责:读写文件public class CustomFile{public void Write() { }public void Read() { }public void OpenToTxt(string file) { }}//单一职责:连接网络public class Sockets{public Sockets(string type) { }private void Bingding() { }private bool CheckNet() { return true; }private void RefreshState() { }}
2、开闭原则
特点: 把类、模块、函数等抽象化,对外扩展,对内不得修改。
含义:用伪代码理解-》
public interface IFile
{
//...不得修改接口内部的代码
}//所谓对外,就是对实现不同的类进行扩展。
//1.扩展 Word 类,Excel 类...
public class Word:IFile,IReader...
{
//2.扩展新功能 void setOutLine();...
}
优点: 新加功能不需要对已有的模块进行修改,而是对外扩展来实现。
反例:
public class OpenFile{public void OpenToTXT(string fileName){Console.Write("Open txt 文件");}public void OpenToPDFReader(string fileName){Console.Write("Open pdf 文件");}//会潜在新需求//比如通过浏览器打开html文件、通过视频软件打开mp4等等//......//该类违反了开闭原则。一旦有新需求就会对该类进行修改代码。//这会影响其他引用该类的代码逻辑}
正例:
//把打开文件模块抽象化public interface IOpenFile{void Open(IFileType fileType);}//把文件类型模块抽象化public interface IFileType{ String format { get; }}//修改特征public class PDFFormat : IFileType{public String format { get { return "PDF"; } }}//修改特征public class SQLFormat : IFileType{public String format { get { return "mdf"; } }}//修改特征public class OpenPDF : IOpenFile{public void Open(IFileType fileType){Console.WriteLine("Opened File is " + fileType.format);}}//扩展新功能public class OpenSQL : IOpenFile{public void Open(IFileType fileType){var bstate = linkSqlManager("123");if (bstate)Console.WriteLine("Opened File is " + fileType.format);}//新功能:因为查看SQL文件,需要先连接数据库private bool linkSqlManager(string pwd){string stateStr = pwd == "123" ? "连接成功" : "连接失败";bool result = pwd == "123" ? true : false;Console.WriteLine(stateStr);return result;}}class Program{static void Main(string[] args){var openPDF = new OpenPDF();openPDF.Open(new PDFFormat());var openSQL = new OpenSQL();openSQL.Open(new SQLFormat());}}
3、依赖倒置原则
特点: 依赖于抽象接口,不依赖于具体实现。
依赖性: A类依赖B类,当B类修改或消失时,对A类会影响很大。
符合依赖倒置原则:
- A类作为主调用者,不应该依赖被调用者B类。A类和B类应当都依赖于抽象。即A类依赖于IA接口,B类依赖于IA接口。
**优点:**降低了模块之间的耦合性。
反例:
假如有制造交通工具的工厂,根据车的型号来生产一辆车。
public class Factory{//Factory 类依赖 Vehicle 类,//当 Vehicle 内部被修改时或者消失掉,将会影响到 Factory 类的 make 方法public void make(Vehicle v) {Console.WriteLine(v.model + v.color);}}//如果工厂需要同时制造一辆自行车和汽车时,则生产的需求就不同了。
//在这样的情况下,会修改Vehicle 类,会可能影响这两种车的制造。
//比如汽车需要设计安全带,自行车需要车篮。public class Vehicle{public string model { get; private set; }public string color { get; private set; }public Vehicle(string model, string color){this.model = model; this.color = color;}}class Program
{
static void Main(string args)
{Vehicle v = new Vehicle("奥迪","黑色");Factory factory = new Factory();factory.make(v);
}
}
正例:
(1)定义设计交通工具的接口:
//设计交通工具抽象化,作为父接口public interface IVehicle{string Model { get; }//车类型string AppearColor { get; }//外观颜色string Design();//设计工作}//设计自行车抽象化,继承 IVehiclepublic interface IBicycle : IVehicle{string Basket { get; }//车篮}//设计汽车抽象化,继承 IVehiclepublic interface ICar : IVehicle{string Safetybelt { get;}//安全带}
(2)实现交通工具的接口:
public class Car: ICar{private string _model;public string Model { get { return _model; } }private string _safetybelt;public string Safetybelt { get { return _safetybelt; } }public Car(sstring model, string safetybelt){_model = model;_safetybelt = safetybelt;}public string Design(){return Model + Safetybelt;}}public class Bicycle : IBicycle{private string _model;public string Model { get { return _model; } }private string _basket;public string Basket { get { return _basket; } }public Bicycle(string model, string basket){_model = model;_basket = basket;}public string Design(){return Model + Basket;}}
(3)定义工厂的接口:
public interface IFactory{string who();}
(4)实现工厂的接口:
public class CarFactory : IFactory{public string who(){return "汽车制造商";}}public class BicycleFactory : IFactory{public string who(){return "自行车制造商";}}
(5)中间类用来处理 IVehicle 接口(父接口) 和 IFactory 接口:
public class Maker{//由于传入参数为原始(父接口)的接口类型,不管外面传入的实现类是什么,将来会修改成什么样子//只要实现类依赖于这些接口,就不会影响到该类执行的代码逻辑。public void Work(IFactory factory, IVehicle vehicle){Console.WriteLine(factory.who() + vehicle.Design());}}class Program{static void Main(string[] args){Maker maker = new Maker();CarFactory carFactory = new CarFactory();Car car = new Car("奥迪", "三点式安全带");maker.Work(carFactory, car);BicycleFactory bicycleFactory = new BicycleFactory();Bicycle bicycle = new Bicycle("欧拜克","灰色车篮");maker.Work(bicycleFactory, bicycle);//工厂类和交通工具类在各自内部之间不存在互相依赖,不存在调用和被调用的关系。//这样就降低了模块之间的耦合性。//maker 作为中间类,Work 方法也只是依赖了接口,而并非实现类。}}
4、里氏替换原则
特点: 定义一个父类,其子类就必须完全继承父类的所有特征。这样父类替换成子类后,也不会有任何变化。
反例:
public abstract class Vehicle{public abstract void Driver();}public class Car : Vehicle{public override void Driver(){}}//把 父类 Vehicle 可以替换成 Car 类来使用,完全不会影响。因为 Car 继承了 Driver 方法。
//但是如果自行车 Bicycle 继承于 Vehicle,问题就来了。public class Bicycle: Vehicle{//继承 Driver 方法显然是不合理的,自行车是骑的,而不是开的public override void Driver() { }}// 也就是说,Bicycle 类没有完全可以实现 Vehicle 里的所有方法属性等。
//所以违反了里氏替换原则
正例:
public abstract class Vehicle{public abstract void Move();}public class Car: Vehicle{public override void Move() { Console.Write("Driver");}}public class Bicycle: Vehicle{public override void Move() { Console.Write("By Bike");}}
5、接口隔离原则
特点:定义一个接口时,不能定义一些不需要的方法属性等。应当要建立在最小的接口上。(接口里的所有特征应当都要被用于实现类上)
反例:
public interface IAnimal{void Eat();void Talk();void Look();void Fly();void Run();void Play();//还有其他行为......}public class Cat: IAnimal{public void Eat() { Console.WriteLine("吃鱼"); }public void Talk() { Console.WriteLine("喵!"); }public void Look() { Console.WriteLine("眨眼"); }public void Fly() { Console.WriteLine("..."); }public void Run() { Console.WriteLine("跑"); }public void Play() { Console.WriteLine("啃纸皮"); }//还有其他行为......//问题1:猫不会飞,自然不要有这样的一种行为出现。即Fly 方法不应该出现。}class Program{static void Main(string[] args){//问题2:Cat 依赖 IAnimal接口后,只看到了猫在玩耍的一种行为。//而其他那些行为,可以说是基本上没什么用了。Cat cat = new Cat();cat.Play();}}
反例2:
//如果把 Animal 接口进一步拆分成:public interface IMouth{void Eat();void Talk();}public interface IEar{void Look();}public interface Iwing{void Fly();void Swim();}public interface IFoot{void Run();void walk();void Climb();}//同样也是违反了接口隔离原则,因为比如:
//Iwing 有 飞和游泳的特征。鱼儿可以用翅膀游泳,小鸟可以扇动翅膀飞翔。
//但是鱼儿不能飞,一些小鸟不能游泳。//显然不满足这个条件:
//接口里的所有特征应当都要被用于实现类上
正例:
//拆分成最小的接口
public interface IEat{void Eat();}public interface IPlay{void Play();}public class Cat:IEat, IPlay{public void Eat() { Console.WriteLine("猫在吃鱼干"); }public void Play() { Console.WriteLine("猫在啃纸皮"); }}//解决1:Eat 和 Play 是猫的行为特征,都是需要的。
//解决2:只定义接口 IEat 和 IPlay,是最小的接口,节省了很多不必要的行为。
//如果有新的需求,猫要喵喵叫,就直接再定义一个“叫”行为的接口。
6、迪米特法则(最少知识原则)
原则1: 减少模块与模块之间的依赖性。比如模块 A 和模块 B 互相依赖,模块C和B互相依赖,而 C 跟 A 没有关系。C 里没有 A的存在,反之亦然。
原则2: 降低模块与模块之间的耦合性。比如 A 被 B 调用,A 类存在于 B 类里。但是 A 的部分成员都设置为私有,不能访问 A 类 的私有成员, B 类只能访问 A类的公有成员。
(public、private 等访问机制,要根据情况合理设定,不要滥用)
优点: 减少模块间的依赖,降低模块间的耦合性。提高代码的复用率。
反例:
根据以上ABC类描述的,数据分析师类作为 C 类,数据管理员类作为 B 类,顾客类作为 A 类。
假定以下代码没有遵循原则1 和原则2:
- 违反原则1:C 类能够直接对A类操作,A存在于C类。
- 违反原则2:A 类的一些pwd、isVIP等重要成员以 public 对外开放,导致外部类可以轻易修改这些成员的逻辑。
//顾客public class Customer{public string pwd;public bool isVIP;public string name { get; private set; }}//数据分析师public class DataAnalyst{// DataAnalyst 和 Customer 存在依赖关系。//如果 Customer 逻辑被修改,则会影响到 DataAnalyst。public void GetCustomersData(DataManager manager){var customers = manager.GetCustomers();var count = customers.Count;//如果 isVIP 字段访问改成 private,则会报错。var vip = customers[0].isVIP;}}//数据管理员public class DataManager{private List<Customer> Customers;public List<Customer> GetCustomers() { return Customers; }}
正例:
//顾客//私有变量限制 DataManager 对 Customer的操作范围public class Customer{private string pwd;private bool _isVIP;private bool isVIP { get { return _isVIP; } }public string name { get; private set; }public void setVip(bool isvip){_isVIP = isvip;}}//数据分析师//只需要通过 DataManager 间接获取 Customer 的一些信息。//保证了 DataAnalyst 和 Customer 不存在依赖关系。//Customer 即便修改了代码逻辑,也影响不了 DataAnalyst。public class DataAnalyst{public void GetCustomersData(DataManager manager){var count = manager.GetCustomerCount();}}//数据管理员public class DataManager{private List<Customer> Customers;private void setVip(int index) { Customers[index].setVip(true); }public int GetCustomerCount() { return Customers.Count; }}
相关文章:
设计模式(一)-设计原则(1)
六大设计原则 1、单一职责原则 特点: 类和方法属性等,都应当遵守单一职责。尽可能保持统一性,单一性。 含义: (1)统一性,定义一个模块就必须要符合所有对象的行为特征。比如声明一个 Animal 类…...

Linux|僵死进程
1.僵死进程产生的原因或者条件: 什么是僵死进程? 当子进程先于父进程结束,父进程没有获取子进程的退出码,此时子进程变成僵死进程. 简而言之,就是子进程先结束,并且父进程没有获取它的退出码; 那么僵死进程产生的原因或者条件就是:子进程先于父进程结束,并且父进程没有获取…...

JDY蓝牙注意事项
波特率设置:9600,不接受115200,或者38400. 不同于WiFi测试,jdy蓝牙不接受AT"指令,可以使用“ATVERSION"指令测试 安信可公司的那个蓝牙指令在这里没有用,不知道是不是生产的公司不一样...

服务器IPMI管理操作
简介:智能平台管理界面(IPMI,Intelligent Platform Management Interface)是管理基于 Intel 结构的企业系统中所使用的外围设备采用的一种工业标准,用户可以利用IPMI监视服务器的物理健康特征,如温度、电压、风扇工作状…...

自动驾驶学习笔记(九)——车辆控制
#Apollo开发者# 学习课程的传送门如下,当您也准备学习自动驾驶时,可以和我一同前往: 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo Beta宣讲和线下沙龙》免费报名—>传送门 文章目录 前言 控制器设计 比例积分微分控制 线性…...

HTML5学习系列之项目实战1
HTML5学习系列之项目实战1 前言代码记录问题总结 前言 学习记录 代码 <div id"player"><audio id"musicbox"></audio><div id"controls" class"clearfix controls"><div id"play" class"…...

git 提交成了LFS格式,如何恢复
平常习惯使用sourceTree提交代码,某次打开时弹出了一个【是否要使用LFS提交】的确认弹窗,当时不知道LFS是什么就点了确认,后续提交时代码全变成了这个样子 因为是初始化的项目首次提交,将近四百个文件全被格式化成了这个样子&…...
【ISP图像处理】Demosaic去马赛克概念介绍以及相关方法整理
1. 基本定义 使用彩色滤光器阵列(CFA)的数码相机需要一个去马赛克程序来形成完整的RGB图像。一般的相机传感器都是采用彩色滤光片阵列(CFA)放置在光感测单元上,在每个像素处仅捕获三种原色成分中的一种。 去马赛克方法主要关注于复原非常规区域,比如边缘…...

单图像3D重建AI算法综述【2023】
计算机视觉是人工智能的一个快速发展的领域,特别是在 3D 领域。 本概述将考虑一个应用任务:2D 和 3D 环境之间的转换。 在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编…...
three.js相机调用reset方法复原但无法完全复原
目录 一、问题 二、原因 三、总结 一、问题 需求:经过多次旋转、平移等变换后,希望恢复到初次渲染的角度、位置。结果发现: three.js oribtControls调用 一次reset方法 无法完全复原;需要多次调用后才能复原。 this.orbitControls.reset…...

前端为什么要工程化
前端为什么要工程化 文章目录 前端为什么要工程化传统开发的弊端一个常见的案例更多问题 工程化带来的优势开发层面的优势团队协作的优势统一的项目结构统一的代码风格可复用的模块和组件代码健壮性有保障团队开发效率高 求职竞争上的优势 现在前端的工作与以前的前端开发已经完…...
软件测试/测试开发/人工智能丨视觉与图像识别自动化测试
视觉与图像识别在软件自动化测试领域中的应用是越来越重要的一项技术,它使得测试可以更全面、准确地模拟用户对图形用户界面(GUI)的交互。以下是视觉与图像识别在软件自动化测试中的主要应用: 1. 自动化 GUI 测试 视觉与图像识别…...

nvm的下载与使用
1.如果已经安装nodejs , 先卸载nodejs; 从控制面板中 卸载程序 卸载nodejs win r打开cmd ,管理员运行 where node 查看是否删除干净nodejs 2.下载nvm 从github 下载nvm , 下载nvm 3.nvm 和node安装路径最好写在同一个路径下 ,如D盘 ,D\a\nvm , D\a\nodejs 4.…...

拼多多官方开放平台接口app商品详情接口获取实时商品详情数据演示
拼多多开放平台提供了一种名为“商品详情接口”的API接口,它允许卖家从自己的系统中快速获取商品信息,如商品标题、描述、价格、库存等,并将这些信息展示在自己的店铺中。通过该接口,卖家可以更好地管理自己的商品库存和销售&…...

STM32F4系列单片机GPIO概述和寄存器分析
第2章 STM32-GPIO口 2.1 GPIO口概述 通用输入/输出口 2.1.1 GPIO口作用 GPIO是单片机与外界进行数据交流的窗口。 2.1.2 STM32的GPIO口 在51单片机中,IO口,以数字进行分组(P0~P3),每一组里面又有8个IO口。 在ST…...

【LeetCode刷题】--9.回文数
9.回文数 class Solution {public boolean isPalindrome(int x) {if(x < 0){return false;}int tmp x, sum 0;boolean flag false;while(x ! 0){sum sum * 10 x % 10;x / 10;}if(sum tmp){flag true;}return flag;} }...

大数据-之LibrA数据库系统告警处理(ALM-12057 元数据未配置周期备份到第三方服务器的任务)
告警解释 系统安装完成后会检查元数据是否有周期备份到第三方服务器的任务,然后每1小时会检查一次。如果元数据未配置周期备份到第三方服务器的任务,将发送严重告警。 在用户创建元数据周期备份到第三方服务器的任务后,告警消除。 告警属性…...

毅速丨嫁接打印在模具制造中应用广泛
在模具行业中,3D打印随形水路已经被广泛认可,它可以提高冷却效率,从而提高产品良率。然而,全打印模具制造的成本相对较高,因为需要使用金属3D打印机和专用材料。为了节省打印成本,同时利用3D打印的优势&…...

『亚马逊云科技产品测评』活动征文|基于next.js搭建一个企业官网
『亚马逊云科技产品测评』活动征文|基于next.js搭建一个企业官网 授权声明:本篇文章授权活动官方亚马逊云科技文章转发、改写权,包括不限于在 Developer Centre, 知乎,自媒体平台,第三方开发者媒体等亚马逊云科技官方…...

C# Winform围棋棋盘
C# Winform简单的围棋棋盘vs2008winform小游戏C#vs2010winform棋盘C#窗体小游戏 这是一个简单的围棋棋盘小游戏,使用C# Winform编写棋盘界面,玩家可以在空白的交叉点上下棋子 项目获取: 项目获取:typora: typora/img (gitee.co…...

CodeBuddy一腾讯内部已有超过 85% 的程序员正在使用de编程工具
大家好,我是程序员500佰,目前正在前往独立开发路线,我会在这里分享关于编程技术、独立开发、技术资讯以及编程感悟等内容。 如果本文能给你提供启发和帮助,还请留下你的一健三连,给我一些鼓励,谢谢。 本文直…...

浅谈未来汽车电子电气架构发展趋势中的通信部分
目录 一、引入 1.1市场占比演化 1.2未来发展趋势 二、纯电动汽车与传统汽车的区别 2.1 纯电车和燃油车的架构(干货) 2.2 新能源汽车的分类 ⚡ 1. 纯电动汽车(BEV) 🔋 2. 插电式混合动力(PHEV&#…...
AI 时代下语音与视频伪造的网络安全危机
引言 在人工智能技术的推动下,语音合成、视频生成等技术取得了突破性进展,Deepfake、AI 语音克隆等工具让语音和视频伪造变得愈发简单且逼真。这些技术在娱乐、影视等领域带来便利的同时,也被不法分子利用,引发了一系列网络安全问…...

STM32+MPU6050传感器
#创作灵感## 在嵌入式系统开发中,STM32F103C8T6单片机与MPU6050传感器的组合因其高性能、低功耗以及丰富的功能而备受青睐。本文将简单介绍如何在Keil 5开发环境中实现STM32F103C8T6与MPU6050的连接和基本数据采集,带你快速入门智能硬件开发。 一、硬件…...
数据库、数据仓库、数据中台、数据湖相关概念
文章目录 序言1数据库,数据仓库,数据中台,数据湖-概念对比释义1.1概念产生的时间顺序1.2在使用功能方面对比1.3在使用工具方面对比 2数据仓库2.1数据仓库的发展阶段2.2 数据仓库的设计2.3数据仓库常用工具,方法2.3.1分析型数据库和…...

【C++项目】负载均衡在线OJ系统-1
文章目录 前言项目结果演示技术栈:结构与总体思路compiler编译功能-common/util.hpp 拼接编译临时文件-common/log.hpp 开放式日志-common/util.hpp 获取时间戳方法-秒级-common/util.hpp 文件是否存在-compile_server/compiler.hpp 编译功能编写(重要&a…...

uni-app学习笔记二十四--showLoading和showModal的用法
showLoading(OBJECT) 显示 loading 提示框, 需主动调用 uni.hideLoading 才能关闭提示框。 OBJECT参数说明 参数类型必填说明平台差异说明titleString是提示的文字内容,显示在loading的下方maskBoolean否是否显示透明蒙层,防止触摸穿透,默…...

一套个人知识储备库构建方案
写文章的初心是做知识沉淀。 好记性不如烂笔头,将阶段性的经验总结成文章,下次遇到相同的问题时,查起来比再次去搜集资料快得多。 然而,当文章越来越多时,有一个问题逐渐开始变得“严峻”起来。 比如,我…...
Flink 失败重试策略 :restart-strategy.type
在 Apache Flink 中,restart-strategy.type 用于指定作业的重启策略(Restart Strategy),它决定了作业在失败后如何恢复。 Flink 提供了 4 种内置重启策略,可以通过 flink-conf.yaml 或代码动态配置。 1. 可配置的 rest…...

【西门子杯工业嵌入式-5-串口实现数据收发】
西门子杯工业嵌入式-5-串口实现数据收发 一、通信基础1.1 什么是通信1.2 嵌入式系统中的通信 二、串行通信原理2.1 串行通信简介2.2 通信参数约定 三、GD32F470 串口资源与性能3.1 串口硬件资源 四、串口通信的实现4.1 串口初始化流程4.2 串口发送函数编写4.3 使用 printf 实现…...