当前位置: 首页 > news >正文

面向对象的设计模式

"万丈高楼平地起,7种模式打地基",模式是一种规范,我们应该站在巨人的肩膀上越看越远,接下来,让我们去仔细了解了解面向对象的7种设计模式

7种设计模式

设计原则的核心思想

  • 找出应用中可能需要变化之处,独立出来,不要和不需要变化的代码混在一起

  • 针对接口编程,而坏是针对实现编程

  • 为了交互对象的耦合性而设计

  • 为了使程序高内聚,低耦合

  • 单一职责低耦合,高内聚

每一个类负责的任务很明确,降低代码之间的耦合度,如果代码耦合度较高,动一点则要动全身,当变化发生时设计或遭受到意想不到的破坏

public class Run {public  void run(){System.out.println("跑步");}
}

在Run类中只负责了Run()的功能,不负责其他的功能,在设计改变类的时候对整体的影响不大

  • 开闭原则适应性和灵活性 稳定性和延续性 可复用性和可维护性

在软件开发的过程中,随着版本的更替,软件的需求会越来越多,如果是修改的内容的话,会很费时,但是我们换个思路,如果在设计模式的时候,我们可以先评估出最容易发生的类,然后对其进行抽象化设计,当变化发生时,只需要增加新的具体类来实现新的业务功能

未使用开/闭原则:

/*开闭原则引入案例*/
public class CarDemo {public static void main(String[] args) {new CarFactory().createCar(1);new CarFactory().createCar(2);new CarFactory().createCar(3);//后期如果需要添加车型,CarFactory需要修改代码//new CarFactory().createCar(4);//new CarFactory().createCar(5);}}/*汽车工程类,专门负责造汽车*/
class CarFactory{/*违反了开闭原则,后期如果添加新的汽车类,则需要修改代码*/public void createCar(int type){if(type==1){System.out.println("造宝马汽车"+new Car("宝马汽车"));}else if(type==2){System.out.println("造奥迪汽车"+new Car("奥迪汽车"));}else{System.out.println("造大众汽车"+new Car("大众汽车"));}}}/*
Car类
*/
class Car{String name;//定义了一个成员变量public Car(String name) {//有参构造函数this.name = name;}
}

使用开/闭原则:

/*
开闭原则案例*/
class CarDemo{public static void main(String[] args) {new CarFactory().carfactory(new BMW());new CarFactory().carfactory(new Aodi());new CarFactory().carfactory(new DaZhong());}}//创建一个CarFactory类
class CarFactory{//创建一个车辆工厂的方法void   carfactory(Car car){car.createCar();}
}//创建一个抽象类Car
abstract  class Car{//创建一个创建车辆的抽象方法public abstract   void createCar();
}/*
如果想添加车辆型号的话,只需要创建一个类继承Car类并实现createCar()方法,不用修改代码
*///继承并重写Car里的方法
class BMW extends Car{@Overridepublic void createCar() {System.out.println("造宝马汽车");}
}//继承并重写Car里的方法
class Aodi extends Car{@Overridepublic void createCar() {System.out.println("造奥迪汽车");}
}//继承并重写Car里的方法
class DaZhong extends Car{@Overridepublic void createCar() {System.out.println("造大众汽车");}
}//继承并重写Car里的方法
class BC extends Car{@Overridepublic void createCar() {System.out.println("造奔驰汽车");Calendar.getInstance();new GregorianCalendar();}
}
  • 里氏替换原则(提高代码的复用性、提高代码的可扩展性 | 继承是具有侵入性的 增大了耦合性 )

基本概念继承必须确保超类锁拥有的性质在子类中仍然成立(子类继承父类后,尽量不要重写父类的方法,可以新增扩展其他的功能.保证子类功能的正确性. 不能让功能修改后,导致程序出错)

主要作用

  1. 里氏替换原则是实现开闭原则的重要方式之一

  1. 克服了继承中重写父类方法造成的可复用性变差的缺点

  1. 功能正确的保证

  1. 加强了程序的健壮性,提高了程序的维护性降低需求变更时引入的风险

代码演练:

/*里氏替换原则演示案例计算器父类
*/public class CalculatorDemo{public static void main(String[] args) {System.out.println(new SuperCalculator().sum(5,5,5));}}
//计算器 基类
class Calculator {//加法public int add(int a,int b){return a+b;}//减法public int sub(int a,int b){return a-b;}
}
/*超级计算器子类
*/
class SuperCalculator extends Calculator{//重写了父类加法@Overridepublic int add(int a, int b) {return a+b+5;}//求和方法 子类新增的功能public int sum(int a,int b,int c){//调用add(),但是子类重写了父类方法,此处调用的子类方法发生了变化int result = this.add(a,b);return result+c;}
}

没有重写父类方法时,输出还是正确结果15,但是重写之后却改变了值,输出了错误的结果20

  • 依赖倒置(都依赖于抽象)

让程序面向抽象类编程、面向接口编程(依赖于抽象接口,对抽象进行编程)

/*依赖倒置引入案例*/
public class WorkerDemo{public static void main(String[] args) {new Worker().getMessage(new DingDing());new Worker().getMessage(new WeChat());//每创建一个信息都要进行修改代码}
}class Worker {public void getMessage(DingDing ding){System.out.println(ding.sendMessage());}public void getMessage(WeChat weChat){System.out.println(weChat.sendMessage());}//每添加一个信息都要进行修改代码
}//钉钉消息
class DingDing{public String sendMessage(){return "钉钉消息";}
}//微信消息
class WeChat{public String sendMessage(){return "微信消息";}
}
/*依赖倒置案例演示*/
public class WorkerDemo{public static void main(String[] args) {new Worker().getMessage(new WeChat());//具有可变性,有较高的适用性}}class Worker {public void getMessage(Message message){System.out.println(message.sendMessage());}}interface Message{public String sendMessage();
}//添加一个信息需要创建一个类实现Message接口
class WeChat implements Message{@Overridepublic String sendMessage() {return "微信消息";}
}
class DingDing implements Message{@Overridepublic String sendMessage() {return "钉钉消息";}
}
  • 接口隔离

使用多个接口,不使用单一的总接口(这个最好理解,在这里就不解释了)

  • 迪米特原则

一个对象应该对其他对象有最少的了解(在一个类中,应尽量少的使用与其没有直接关系的类)

直接关系

  1. 类中的成员属性

  1. 在类中的方法作为参数使用

  1. 在类中的方法作为返回值类型

注意事项

  1. 核心是降低类之间的耦合

  1. 从被依赖折者的角度来看,尽量将逻辑封装在类的内部,对外除了提供的public方法,不泄露任何信息

  1. 从依赖者的角度来说,只依赖应该依赖的对象

  1. 切记不要为了用而用

代码实现:

public class Demeter {public static void main(String[] args) {new SchoolManger().printAllEmployee(new CollegeManger());}
}/*学校员工类*/
class SchoolEmployee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}/*学院员工类*/
class CollegeEmployee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}//学院员工管理管理类
class CollegeManger{//生成学院所有的员工public List<CollegeEmployee> getCollegeEmployee(){ArrayList<CollegeEmployee> collegeEmployeeArrayList = new ArrayList<>();for (int i = 0; i <10 ; i++) {CollegeEmployee collegeEmployee = new CollegeEmployee();collegeEmployee.setId("学院员工的id="+i); //添加学院员工collegeEmployeeArrayList.add(collegeEmployee);}return collegeEmployeeArrayList;}}
//学校员工管理类
class SchoolManger {//生成学校的员工public List<SchoolEmployee> getSchoolEmployee() {ArrayList<SchoolEmployee> employeeArrayList = new ArrayList<>();for (int i = 0; i < 5; i++) {SchoolEmployee employee = new SchoolEmployee();employee.setId("学校的员工id=" + i);employeeArrayList.add(employee);}return employeeArrayList;}//输出学校员工和学院员工信息public void printAllEmployee(CollegeManger collegeManger) {//获取到学校员工List<SchoolEmployee> employeeArrayList = this.getSchoolEmployee();System.out.println("--------学校员工--------");for (SchoolEmployee employee1 : employeeArrayList) {System.out.println(employee1.getId());}System.out.println("--------学院员工--------");List<CollegeEmployee> collegeEmployees = collegeManger.getCollegeEmployee();//此处学校管理类中出现CollegeEmployee,此类与SchoolManger并非直接朋友,不合理for (CollegeEmployee collegeEmployee : collegeEmployees) {System.out.println(collegeEmployee.getId());}}
}
public class Demeter {public static void main(String[] args) {new SchoolManger().printAllEmployee(new CollegeManger());}
}/*学校员工类*/
class SchoolEmployee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}/*学员员工类*/
class CollegeEmployee{private String id;public void setId(String id){this.id = id;}public String getId(){return id;}
}//学院员工管理管理类
class CollegeManger{//生成学员所有的员工public List<CollegeEmployee> getCollegeEmployee(){ArrayList<CollegeEmployee> collegeEmployeeArrayList = new ArrayList<>();for (int i = 0; i <10 ; i++) {CollegeEmployee collegeEmployee = new CollegeEmployee();collegeEmployee.setId("学院员工的id="+i); //添加学院员工collegeEmployeeArrayList.add(collegeEmployee);}return collegeEmployeeArrayList;}public void printCollegeEmployee(){List<CollegeEmployee> collegeEmployee = getCollegeEmployee();for (CollegeEmployee employee : collegeEmployee) {System.out.println("学员员工id="+employee.getId());}}}
//学校员工管理类
class SchoolManger {//生成学校的员工public List<SchoolEmployee> getSchoolEmployee() {ArrayList<SchoolEmployee> employeeArrayList = new ArrayList<>();for (int i = 0; i < 5; i++) {SchoolEmployee employee = new SchoolEmployee();employee.setId("学校的员工id=" + i);employeeArrayList.add(employee);}return employeeArrayList;}//输出学校员工和学院员工信息public void printAllEmployee(CollegeManger collegeManger) {//获取到学校员工List<SchoolEmployee> employeeArrayList = this.getSchoolEmployee();System.out.println("--------学校员工--------");for (SchoolEmployee employee1 : employeeArrayList) {System.out.println(employee1.getId());}//CollegeManger与SchoolManger是直接朋友,相互之间访问System.out.println("--------学员员工-----------");collegeManger.printCollegeEmployee();}
}
  • 组合/聚合复用原则(优先使用组合,使系统更灵活,其次才考虑继承,达到复用的目的)

代码实现:

/*组合/聚合复用原则案例1  使用依赖实现复用*/
public class A {public void method01() {}public void method02() {}
}class B extends A {private A a;public void method() {}
}class Test {public static void main(String[] args) {new B().method01();new B().method02();}
}
/*组合/聚合复用原则案例2  使用组合/聚合实现复用*/
public class A {public void method01(){}public void method02(){}
}class B{A a;public void setA(A a){this.a = a;}public void use(){a.method01();a.method02();}}class Test{public static void main(String[] args) {A a = new A();B b = new B();b.setA(a);b.use();}
}
/*组合/聚合复用原则案例3  使用依赖实现复用*/
public class A {public void method01(){}public void method02(){}
}class B{public void use(A a){a.method01();a.method02();}}class Test{public static void main(String[] args) {A a = new A();B b = new B();b.use(a);}
}

相关文章:

面向对象的设计模式

"万丈高楼平地起&#xff0c;7种模式打地基"&#xff0c;模式是一种规范&#xff0c;我们应该站在巨人的肩膀上越看越远&#xff0c;接下来&#xff0c;让我们去仔细了解了解面向对象的7种设计模式7种设计模式设计原则的核心思想&#xff1a;找出应用中可能需要变化之…...

里氏替换原则|SOLID as a rock

文章目录 意图动机:违反里氏替换原则解决方案:C++中里氏替换原则的例子里氏替换原则的优点1、可兼容性2、类型安全3、可维护性在C++中用好LSP的标准费几句话本文是关于 SOLID as Rock 设计原则系列的五部分中的第三部分。 SOLID 设计原则侧重于开发 易于维护、可重用和可扩展…...

【C++】右左法则,指针、函数与数组

右左法则——判断复杂的声明对于一个复杂的声明&#xff0c;可以用右左法则判断它是个什么东西&#xff1a;1.先找到变量名称2.从变量名往右看一个部分&#xff0c;再看变量名左边的一个部分3.有小括号先看小括号里面的&#xff0c;一层一层往外看4.先看到的东西优先级大&#…...

打通数据价值链,百分点数据科学基础平台实现数据到决策的价值转换 | 爱分析调研

随着企业数据规模的大幅增长&#xff0c;如何利用数据、充分挖掘数据价值&#xff0c;服务于企业经营管理成为当下企业数字化转型的关键。 如何挖掘数据价值&#xff1f;企业需要一步步完成数据价值链条的多个环节&#xff0c;如数据集成、数据治理、数据建模、数据分析、数据…...

C++之多态【详细总结】

前言 想必大家都知道面向对象的三大特征&#xff1a;封装&#xff0c;继承&#xff0c;多态。封装的本质是&#xff1a;对外暴露必要的接口&#xff0c;但内部的具体实现细节和部分的核心接口对外是不可见的&#xff0c;仅对外开放必要功能性接口。继承的本质是为了复用&#x…...

ThingsBoard-RPC

1、使用 RPC 功能 ThingsBoard 允许您将远程过程调用 (RPC) 从服务器端应用程序发送到设备,反之亦然。基本上,此功能允许您向/从设备发送命令并接收命令执行的结果。本指南涵盖 ThingsBoard RPC 功能。阅读本指南后,您将熟悉以下主题: RPC 类型;基本 RPC 用例;RPC 客户端…...

java分治算法

分治算法介绍 分治法是一种很重要的算法。字面上的解释是“分而治之”&#xff0c;就是把一个复杂的问题分成两个或更多的相同或 相似的子问题&#xff0c;再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解&#xff0c;原问题的解即子问题 的解的合并。这个技…...

【Flutter】【Unity】使用 Flutter + Unity 构建(AR 体验工具包)

使用 Flutter Unity 构建&#xff08;AR 体验工具包&#xff09;【翻译】 原文&#xff1a;https://medium.com/potato/building-with-flutter-unity-ar-experience-toolkit-6aaf17dbb725 由于屡获殊荣的独立动画工作室 Aardman 与讲故事的风险投资公司 Fictioneers&#x…...

MC0108白给-MC0109新河妇荡杯

MC0108白给 小码哥和小码妹在玩一个游戏&#xff0c;初始小码哥拥有 x的金钱&#xff0c;小码妹拥有 y的金钱。 虽然他们不在同一个队伍中&#xff0c;但他们仍然可以通过游戏的货币系统进行交易&#xff0c;通过互相帮助以达到共赢的目的。具体来说&#xff0c;在每一回合&a…...

求职(JAVA程序员的面试自我介绍)

背景 在找工作的过程中&#xff0c;在面试的环节&#xff0c;大多数面试官首先都会叫你自我介绍一下。一般是3到5分钟内。不过经过我面试的无数的公司还有曾经也面试过大多数的求职者。国内很多的程序员面试都极其不专业。有一种很随心所欲的感觉。所以经常遇到求职者吐槽遇到了…...

金三银四季节前端面试题复习来了

vue3和vue2的区别有哪些 Diff算法的改进Tree Sharing优化主要的API双向绑定改为es6的proxy原生支持tscomposition API移除令人头疼的this 说说CSS选择器以及这些选择器的优先级 !important 内联样式&#xff08;1000&#xff09; ID选择器&#xff08;0100&#xff09; 类选…...

【C/C++基础练习题】简单语法使用练习题

&#x1f349;内容专栏&#xff1a;【C/C要打好基础啊】 &#x1f349;本文内容&#xff1a;简单语法使用练习题&#xff08;复习之前写过的实验报告&#xff09; &#x1f349;本文作者&#xff1a;Melon西西 &#x1f349;发布时间 &#xff1a;2023.2.10 目录 1、输入三个数…...

堆排序

章节目录&#xff1a;一、相关概述1.1 基本介绍1.2 排序思想二、基本应用2.1 步骤说明2.2 代码示例三、结束语一、相关概述 1.1 基本介绍 堆排序是利用堆这种数据结构而设计的一种排序算法&#xff0c;堆排序是一种选择排序。它的最坏最好平均时间复杂度均为 O(nlogn)&#x…...

PLC是什么?PLC相关知识小科普

欢迎各位来到东用知识小课堂1.PLC是什么&#xff1a;●PLC就是可编程控制器&#xff0c;它应用于工业环境&#xff0c;必须具有很强的抗干扰能力、广泛的适应能力和应用范围。●PLC是“数字运算操作的电子系统”&#xff0c;也是一种计算机&#xff0c;它是“专为在工业环境下应…...

BERT简介

BERT&#xff1a; BERT预训练模型训练步骤&#xff1a; 使用Masked LM方式将语料库中的某一部分的词语掩盖住&#xff0c;模型通过上下文预测被掩盖的信息&#xff0c;从而训练出初步的语言模型在语料库中选出连续的上下语句&#xff0c;并使用Tranformer模块识别语句的连续性通…...

OpenStack云平台搭建(5) | 部署Nova

目录 1、登录数据库配置 2、安装nova 3、计算节点上安装nova 4、在controller节点上 nova组件是用来建虚拟机的&#xff08;功能&#xff1a;负责响应虚拟机创建请求、调度、销毁云主机&#xff09; nova主要组成&#xff1a; (1).nova api service------安装在controlle…...

【重要】2023年上半年有三AI新课程规划出炉,讲师持续招募中!

2023年正式起航&#xff0c;想必大家都已经完全投入到了工作状态中&#xff0c;有三AI平台今年将在已有内容的基础上&#xff0c;继续进行新课程开发&#xff0c;本次我们来介绍今年上半年的课程计划&#xff0c;以及新讲师招募计划。2023年新上线课程我们平台的课程当前分为两…...

【正点原子FPGA连载】第八章UART串口中断实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第八章UART串口中…...

【云原生】解读Kubernetes三层网络方案

在上一篇文章中&#xff0c;我以网桥类型的 Flannel 插件为例&#xff0c;为你讲解了 Kubernetes 里容器网络和 CNI 插件的主要工作原理。不过&#xff0c;除了这种模式之外&#xff0c;还有一种纯三层&#xff08;Pure Layer 3&#xff09;网络方案非常值得你注意。其中的典型…...

elasticsearch8.3.2搭建部署

Elasticsearch8.3.2搭建部署详细步骤 0.过往文章 ES-6文章&#xff1a; Elasticsearch6.6.0部署、原理和使用介绍: https://blog.csdn.net/wt334502157/article/details/119515730 ES-7文章&#xff1a; Elasticsearch7.6.1部署、原理和使用介绍: https://blog.csdn.net/wt…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...