设计模式之7大设计原则-Java版

软件设计模式是前辈们代码设计经验的总结,可以反复使用。设计模式共分为3大类,创建者模式(5种)、结构型模式(7种)、行为型模式(11种),一共23种设计模式,软件设计一般需要满足7大基本原则。下面通过5章的学习一起来看看设计模式的魅力吧。

目录

1.1、设计模式概述

1.2、设计模式的分类

1.3、UML类图

1.4、设计原则

1.4.1 开闭原则

1.4.2、里式代换原则

1.4.3、依赖倒转原则

1.4.4、接口隔离原则

1.4.5、迪米特法则

1.4.6、合成复用原则

1.4.7、单一职责原则


1.1、设计模式概述

软件设计模式是前辈们代码设计经验的总结,本质上是对面向对象设计原则的实际应用,是对类的封装、继承、多态以及类的关联关系与组合关系的充分理解。

使用设计模式的代码可重用性与可维护性高、可读性强、可以减少软件开发周期,提升开发效率。

1.2、设计模式的分类

创建型模式(5种):本质上就是将对象的创建与使用分离,就是描述怎样去创建对象。

包括:单例、原型、工厂方法、抽象工厂、建造者模式

结构型模式(7种):本质上是将类或者对象按照某种布局组成更大的结构。

包括:代理、适配器、桥接、装饰、外观、享元、组合模式

行为模式(11种):本质是描述类与对象协助完成单个对象无法完成的任务,以及怎么分配职责。

包括:模板方法、策略、命令、责任链、状态、观察者、中介者模式、迭代器、访问者、备忘录、解释器。

1.3、UML类图

类图是面向对象建模的主要组成部门,类图显示了模型的内部结构,主要包括:模型中存在的类、类的属性以及类与类之间的关系等。

1.4、设计原则

设计模式的7大原则,具体如下:

1.开闭原则:软件实体 (类、模块、函数等等) 应该是可以被扩展的,但是不可被修改。

2.里式代换原则:继承的时候尽量不要重写父类的方法,如果重写要保证不破坏原方法的功能。

3.依赖倒转原则:抽象不应该依赖于细节,细节应该依赖于抽象,依赖接口,面向接口编程。

4.接口隔离原则:客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。

5.迪米特法则:最少知道原则,它表示一个对象应该对其它对象保持最少的了解。通俗来说就是,只与直接的朋友通信。

6.合成复用原则:通过组合或者聚合的方式替代继承,增强封装性与提升复用的灵活性。

7.单一职责:表示一个模块的组成元素之间的功能相关性,即一个类只负责一项职责。

1.4.1 开闭原则

1.开闭原则:对扩展开放,对修改关闭。扩展源程序的时候,不要修改原有代码,通过使用接口与抽象类实现。

通过定义一个抽象类,抽象类中定义抽象方法,通过多个子类继承抽象类并重写重写抽象方法,同时设置一个中间类用于注入抽象类并调用抽象方法,这样在客户端测试类中就可以实例化中间类,并注入抽象类的子类,即实现了扩展类方法,也没更改代码本身。

1.定义一个抽象类,如下:

/*** @ClassName AbstractSkin* @description: 抽象皮肤类* @author nuist__NJUPT* @date 2024年01月18日* @version: 1.0*/
public abstract class AbstractSkin {// 显示方法public abstract void display() ;}

2.定义两个子类,继承抽象类并实现抽象方法display


/*** @ClassName DefaultSkin* @description: 默认皮肤* @author nuist__NJUPT* @date 2024年01月18日* @version: 1.0*/
public class DefaultSkin extends AbstractSkin{@Overridepublic void display() {System.out.println("默认皮肤");}}
/*** @author nuist__NJUPT* @ClassName NewSkin* @description: 新皮肤* @date 2024年01月18日* @version: 1.0*/
public class NewSkin extends AbstractSkin {@Overridepublic void display() {System.out.println("新皮肤");}
}

3.定义一个中间类,在中间类中注入抽象类,并调用抽象方法。

/*** @author nuist__NJUPT* @ClassName SogouInput* @description: 搜狗输入法* @date 2024年01月18日* @version: 1.0*/
public class SogouInput {private AbstractSkin abstractSkin ;public void setAbstractSkin(AbstractSkin abstractSkin) {this.abstractSkin = abstractSkin;}public void display(){abstractSkin.display();}
}

4.定义一个客户端测试类,在测试类中实例化中间类,并注入实例化子类,即可调用子类方法

/*** @author nuist__NJUPT* @ClassName Client* @description: TODO* @date 2024年01月18日* @version: 1.0*/
public class Client {public static void main(String[] args) {//1.创建搜狗输入法对象SogouInput sogouInput = new SogouInput() ;//2.创建皮肤对象并将皮肤设置到输入法sogouInput.setAbstractSkin(new DefaultSkin());// sogouInput.setAbstractSkin(new NewSkin());//4.显示皮肤sogouInput.display();}}
1.4.2、里式代换原则

里式代换原则:子类可以扩展父类的功能,但是不允许更改父类的内容。

子类继承父类得时候,可以新增方法,但是尽量不要重写父类当中得方法

这里通过定义接口,在接口中定义方法,通过实现类的方式实现接口中方法的功能。

1.定义四边形接口,并定义获取长于宽的方法。


/*** @author nuist__NJUPT* @InterfaceName Quadrilateral* @description: 四边形接口* @date 2024年01月18日* @version: 1.0*/
public interface Quadrilateral {double getLength() ;double getWidth() ;}

2.定义四边形接口的两个实现类,正方法与长方形。

/*** @author nuist__NJUPT* @ClassName Rectangle* @description: 长方形实现类* @date 2024年01月18日* @version: 1.0*/
public class Rectangle implements Quadrilateral {private double length ;private  double width ;public void setLength(double length) {this.length = length;}public void setWidth(double width) {this.width = width;}@Overridepublic double getLength() {return length;}@Overridepublic double getWidth() {return width;}
}
/*** @author nuist__NJUPT* @ClassName Square* @description: 正方形实现类* @date 2024年01月18日* @version: 1.0*/
public class Square implements Quadrilateral {private double side ;public double getSide() {return side;}public void setSide(double side) {this.side = side;}@Overridepublic double getLength() {return side;}@Overridepublic double getWidth() {return side;}
}

3.定义测试类,测试通过实现类进行扩充长宽并打印。

import com.company.p1.demo2.Rectangle;/*** @author nuist__NJUPT* @ClassName RectangleDemo* @description: 测试类* @date 2024年01月18日* @version: 1.0*/
public class RectangleDemo {public static void main(String[] args) {Rectangle rectangle = new Rectangle() ;rectangle.setLength(20);rectangle.setWidth(10);resize(rectangle);print(rectangle);}/*** 扩宽方法* @param rectangle*/public static void resize(com.company.p1.demo2.Rectangle rectangle){// 宽比长小则扩充while(rectangle.getLength() >= rectangle.getWidth()){rectangle.setWidth(rectangle.getWidth() + 1);}}/*** 打印长与宽* @param rectangle*/public static void print(Rectangle rectangle){System.out.println("长方形的长为:" + rectangle.getLength());System.out.println("长方形的宽为:" + rectangle.getWidth());}}
1.4.3、依赖倒转原则

依赖倒转原则:模块应该依赖于抽象,就是面向抽象编程,而不是对实现进行编程,这样可以降低客户与实现之间的耦合。具体说就是依赖接口,而不是依赖具体的实现类。

首先定义三个接口,硬盘,内存,cpu的如下:


/*** @author nuist__NJUPT* @InterfaceName HardDisk* @description: 硬盘接口* @date 2024年01月18日* @version: 1.0*/
public interface HardDisk {// 存储数据public void save(String data) ;// 获取数据public String get() ;
}
/*** @author nuist__NJUPT* @InterfaceName Cpu* @description: CPU接口* @date 2024年01月18日* @version: 1.0*/
public interface Cpu {public void run() ;}

/*** @author nuist__NJUPT* @InterfaceName Memory* @description: 内存条接口* @date 2024年01月18日* @version: 1.0*/
public interface Memory {//存储数据的接口public void save() ;}

然后分别定义三个接口的实现类,如下:


/*** @author nuist__NJUPT* @ClassName XiJieHardDisk* @description: 硬盘实现类* @date 2024年01月18日* @version: 1.0*/
public class XiJieHardDisk implements HardDisk {@Overridepublic void save(String data) {System.out.println("使用希捷硬盘存储数据");}@Overridepublic String get() {return "从硬盘中获取的数据" ;}
}
/*** @author nuist__NJUPT* @ClassName IntelCpu* @description: Intel的CPU* @date 2024年01月18日* @version: 1.0*/
public class IntelCpu implements Cpu {@Overridepublic void run() {System.out.println("运行Intel的cpu");}
}
/*** @author nuist__NJUPT* @ClassName KingstonMemory* @description: TODO* @date 2024年01月18日* @version: 1.0*/
public class KingstonMemory implements Memory {@Overridepublic void save() {System.out.println("使用金士顿内存条");}
}

然后定义一个中间类,用于依赖这些接口,而不是这些实现类。

/*** @author nuist__NJUPT* @ClassName Computer* @description: 计算机类* @date 2024年01月18日* @version: 1.0*/
public class Computer {/*** 依赖的是抽象接口,而不是具体的实现类,这样后面增加新的实现类不需要改动Computer* 只需要增加实现类,并且在测试类中进行实例化就可以了*/private HardDisk hardDisk ;private Cpu cpu ;private Memory memory ;public HardDisk getHardDisk() {return hardDisk;}public void setHardDisk(HardDisk hardDisk) {this.hardDisk = hardDisk;}public Cpu getCpu() {return cpu;}public void setCpu(Cpu cpu) {this.cpu = cpu;}public Memory getMemory() {return memory;}public void setMemory(Memory memory) {this.memory = memory;}/*** 运行计算机的方法*/public void run(){System.out.println("运行计算机");System.out.println("从硬盘上获取的数据:" + hardDisk.get());cpu.run();memory.save();}
}

最后定义测试类,在测试类中实例化中间类与实现类,并调用实现类的方法,在测试类中依赖具体,而不是在中间类,中间类依赖的是抽象的接口。这样在就可以避免中间层的代码修改,只需要增加实现类然后在测试类,也就是客户端修改代码即可。

/*** @author nuist__NJUPT* @ClassName ComputerDemo* @description: 测试类* @date 2024年01月18日* @version: 1.0*/
public class ComputerDemo {public static void main(String[] args) {HardDisk hardDisk = new XiJieHardDisk() ;Cpu cpu = new IntelCpu() ;Memory memory = new KingstonMemory() ;Computer computer = new Computer() ;computer.setCpu(cpu);computer.setMemory(memory);computer.setHardDisk(hardDisk);computer.run();}}
1.4.4、接口隔离原则

接口隔离原则:一个类对另外一个类的依赖应该建立在最小的接口上,也就是定义接口的功能最小化,然后通过实现类的方式重写接口中的抽象方法即可,这样可以避免客户端依赖的方法是它并不使用的。

1.定义三个相互隔离的最小化接口,而不是定义一个接口包含三个方法,避免实现类依赖不使用的方法。


/*** @author nuist__NJUPT* @InterfaceName AntiTheft* @description: 防盗接口* @date 2024年01月18日* @version: 1.0*/
public interface AntiTheft {void antiTheft() ;}
/*** @author nuist__NJUPT* @InterfaceName Fireproof* @description: 防火接口* @date 2024年01月18日* @version: 1.0*/
public interface Fireproof {void fireproof() ;
}
/*** @author nuist__NJUPT* @InterfaceName Waterproof* @description: 防水接口* @date 2024年01月18日* @version: 1.0*/
public interface Waterproof {void waterproof() ;
}

2.定义多个实现类,分别实现接口并重写接口中的抽象方法,需要用到接口方法的,才去实现接口。

/*** @author nuist__NJUPT* @ClassName SafeDoor* @description: TODO* @date 2024年01月18日* @version: 1.0*/
public class SafeDoor implements AntiTheft, Fireproof, Waterproof {@Overridepublic void antiTheft() {System.out.println("防盗");}@Overridepublic void fireproof() {System.out.println("防火");}@Overridepublic void waterproof() {System.out.println("防水");}
}
/*** @author nuist__NJUPT* @ClassName SafeDoor2* @description: TODO* @date 2024年01月18日* @version: 1.0*/
public class SafeDoor2 implements AntiTheft, Fireproof{@Overridepublic void antiTheft() {System.out.println("防盗");}@Overridepublic void fireproof() {System.out.println("防火");}
}

3.在测试类中实例化实现类,并调用相应的实现方法。


/*** @author nuist__NJUPT* @ClassName Client* @description:测试类* @date 2024年01月18日* @version: 1.0*/
public class Client {public static void main(String[] args) {// 实例化对象SafeDoor safeDoor = new SafeDoor() ;safeDoor.antiTheft();safeDoor.fireproof();safeDoor.waterproof();System.out.println("-----------------------------");SafeDoor2 safeDoor2 = new SafeDoor2() ;safeDoor2.antiTheft();safeDoor2.fireproof();}
}
1.4.5、迪米特法则

迪米特法则:最少只知识原则,也就是说如果两个实体无需直接通信,就尽量不要产生直接交互,这样可以降低模块的耦合度,提高模块的独立性。

1、首先定义三个类,分别为公司类、明星类、粉丝类

/*** @author nuist__NJUPT* @ClassName Company* @description: 公司类* @date 2024年01月18日* @version: 1.0*/
public class Company {private String name ;public Company(String name) {this.name = name;}public String getName() {return name;}
}
/*** @author nuist__NJUPT* @ClassName Star* @description: 明星类* @date 2024年01月18日* @version: 1.0*/
public class Star {private String name ;public Star(String name) {this.name = name;}public String getName() {return name;}
}
/*** @author nuist__NJUPT* @ClassName Fans* @description: 粉丝类* @date 2024年01月18日* @version: 1.0*/
public class Fans {private String name ;public Fans(String name) {this.name = name;}public String getName() {return name;}}

2、定义一个经纪人的类,通过该类实现明星与粉丝,以及明星与公司的交互,避免它们直接交互,降低模块的耦合性,提高模块的独立性。

/*** @author nuist__NJUPT* @ClassName Agent* @description: 经纪人类* @date 2024年01月18日* @version: 1.0*/
public class Agent {private Star star ;private Company company ;private Fans fans ;public Star getStar() {return star;}public void setStar(Star star) {this.star = star;}public Company getCompany() {return company;}public void setCompany(Company company) {this.company = company;}public Fans getFans() {return fans;}public void setFans(Fans fans) {this.fans = fans;}/*** 粉丝见面方法*/public void meeting(){System.out.println("明星:" + star.getName() + "与粉丝:" + fans.getName()+"见面");}/*** 与公司洽谈*/public void business(){System.out.println("明星:" + star.getName() + "与公司:" + company.getName()+"洽谈");}}

3.最后在测试类实例化经纪人类,并调用相应的方法。

/*** @author nuist__NJUPT* @ClassName Client* @description: 测试类* @date 2024年01月18日* @version: 1.0*/
public class Client {public static void main(String[] args) {Agent agent = new Agent() ;agent.setStar(new Star("刘德华"));agent.setCompany(new Company("大碗娱乐公司"));agent.setFans(new Fans("张三"));agent.meeting();agent.business();}
}
1.4.6、合成复用原则

合成复用原则:尽量使用组合或者聚合等关联关系来实习复用,而不是通过继承的方式实现复用

因为继承首先破环了类的封装性,父类暴露给子类了,同时子类与父类的耦合度高,另外继承限制了复用的灵活性。

1.4.7、单一职责原则

单一职责原则,通俗的来说就是尽量让一个类中只负责一件事,当然这个还是要结合实际情况来看。有些场景可以一个类中做多件事,然后子类继承并重写方法。

我们假设有两种动物,分别呼吸空气与水,那么可以定义两个类,每个类中定义一个方法。这样满足单一职责原则。

/*** @author nuist__NJUPT* @ClassName Client* @description: 单一职责测试类* @date 2024年01月19日* @version: 1.0*/
class Terrestrial{public void breathe(String animal){System.out.println(animal + "呼吸空气");}
}
class Aquatic{public void breathe(String animal){System.out.println(animal + "呼吸水");}
}public class Client{public static void main(String[] args){Terrestrial terrestrial = new Terrestrial();terrestrial.breathe("牛");terrestrial.breathe("羊");terrestrial.breathe("猪");Aquatic aquatic = new Aquatic();aquatic.breathe("鱼");}
}  

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

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

相关文章

当MySql有字段为null,索引是否会失效

sql执行过程中,使用is null 或者is not null 理论上都会走索引,由于优化器的原因导致索引失效变成全表扫描,或者说是否使用索引和NULL值本身没有直接关系,和执行成本有关系。 数据行记录如何存储NULL值的? InnoDB 提供了 4 种行格式 Redundant:非紧凑格式,5.0 版…

01.CheckStyle代码检查工具

CheckStyle代码检查工具 1.介绍 Checkstyle 是一种开发工具,可帮助程序员编写符合编码标准的 Java 代码。它使检查 Java 代码的过程自动化,从而使开发者免于完成这项无聊(但重要)的任务。这使得它非常适合想要强制执行编码标准的…

What is `JsonSanitizer.sanitize` does?

JsonSanitizer.sanitize 是一个Java库中的方法,用于处理和净化JSON字符串,特别是针对跨站脚本攻击(XSS, Cross-Site Scripting)。 例如,在处理富文本内容、用户评论、从第三方服务获取的数据时,使用 JsonSa…

高级架构师是如何设计一个系统的?

架构师如何设计系统? 系统拆分 通过DDD领域模型,对服务进行拆分,将一个系统拆分为多个子系统,做成SpringCloud的微服务。微服务设计时要尽可能做到少扇出,多扇入,根据服务器的承载,进行客户端负…

123 二叉树的序列化于反序列化

问题描述:序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个九四u安吉环境,采用相反的重构方式得到原数据,请设计一个算法实现…

微信这个费用,终于降低了

大家好,我是小悟 这个费用降低了,这对于广大小程序开发者来说无疑是一个好消息。这一举措不仅可以降低开发者的成本,还有助于激发更多的创新和创业激情。 对于广大小程序开发者来说,这也是一个福音,因为他们可以降低开…

DMA技术在STM32中优化UART、SPI和I2C通信性能的研究与实现

DMA(Direct Memory Access,直接存储器访问)技术可以在STM32微控制器上优化UART、SPI和I2C等通信性能。DMA可以实现数据的高速传输,减轻CPU的负担,提高系统性能。在本篇文章中,我将探讨DMA技术在STM32中优化…

【计算机组成原理】

【第一章】计算机系统概述 【第二章】进程管理

RDMA编程实践-SEND-RECEICVE原语应用

RDMA编程实践 本文描述了RDMA编程过程中的SEND-RECEIVE双边原语的代码实现。包含多个版本,1、client向server发送消息,server回复client收到消息(ACK),然后两边断开连接。2、server端循环等待客户端建立连接,client发送一次消息后…

rocketmq双主双从部署+dashbord

1、主机规划 主机节点地址主机Anamesrv192.168.2.228:9876主机Abroker-a192.168.2.228:10911主机Abroker-b192.168.2.228:11911主机Bnamesrv192.168.2.229:9876主机Bbroker-c192.168.2.229:10911主机Bbroker-d192.168.2.229:11911 2、两台主机都需要执行,创建mq需…

Javaweb之SpringBootWeb案例员工管理之删除员工的详细解析

3.3 删除员工 查询员完成之后,我们继续开发新的功能:删除员工。 3.3.1 需求 当我们勾选列表前面的复选框,然后点击 "批量删除" 按钮,就可以将这一批次的员工信息删除掉了。也可以只勾选一个复选框,仅删除一…

超详细的 pytest 钩子函数 —— 之初始钩子和引导钩子来啦!

前几篇文章介绍了 pytest 点的基本使用,学完前面几篇的内容基本上就可以满足工作中编写用例和进行自动化测试的需求。从这篇文章开始会陆续给大家介绍 pytest 中的钩子函数,插件开发等等。 仔细去看过 pytest 文档的小伙伴,应该都有发现 pyt…

PSP - 提取 UniRef 数据库搜索的 MSA 序列物种 (Species) 信息

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/135702185 UniRef库:UniProt参考聚类(UniRef)的简称,提供了从UniProt知识库(包括异构体…

[力扣 Hot100]Day7 接雨水

题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 出处 思路 就是寻找“凹”形区间,找使得左右两端点为最大的两个值的最长区间。这里我分了两种情况,右边大于等于左边…

智慧校园安防系统功能 平安校园、宿舍管理的智慧校园解决方案---豌豆云

从“校园空间”出发,贴合“教学与教务”管理诉求,以“人脸识别”技术作为“身份管理”的立足点,融合“物联网和大数据”多项能力。 打造涵盖“通行考勤、平安校园、宿舍管理、会议签到和人脸支付”在内的智慧校园解决方案,助力校…

MySQL深度分页优化问题

☆* o(≧▽≦)o *☆嗨~我是小奥🍹 📄📄📄个人博客:小奥的博客 📄📄📄CSDN:个人CSDN 📙📙📙Github:传送门 📅&a…

C语言基础入门48篇_00_如何学习一门新语言(针对初学者)

程序员之道,万变不离其宗,说相声讲究的是说、学、逗、唱,学习程序最快也是最好的办法就是:过、抄、仿、改、调、看、练、创、悟: 文章目录 1、过:2、抄代码:3、模仿改:4、勤调试&…

RenderDoc 增加 DXBC to HLSL 的 shader viewer

目的 便于后续抓帧出来的 DXBC 转为 HLSL,提高可读性 原因 编写的原因,因为按照网上的大佬的BLOG,发现某个 etnlGD/HLSLDecompiler 上的工具使用上是有问题的 (有可能是以前的 render doc 版本没有问题,而我现在是在…

字符串算法总结|双指针的总结

在字符串旋转操作中主要是运用多次反转,最后得到结果。 例如反转字符串里的单词:可以先进行整体反转,最后进行单词反转。 例如从字符串的倒数第k位开始反转,此时可以先整体反转,在局部反转,在反转时可以用…

KubeSphere平台使用

KubeSphere官网地址:https://kubesphere.io/zh/ KubeKey一键部署K8S集群:https://kubesphere.io/zh/docs/v3.4/installing-on-linux/introduction/multioverview/ 一台master node(初始化主节点)、两台 work node( joi…