设计模式之设计原则

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 1.单一职责原则单一职责原则:类的职责单一,不能将太多的职责放在一个类中,该原则是实现高内聚、低耦合的指导方针比如:进行登录操作需要经过用户请求、参数校验、查找用户、连接数据库、操作数据库等这些操作开闭原则:一个软件应当对扩展开发、对修改关闭。即在不修改源代码的情况下改变对象的行为比如:我们现在需要查看报表,但是由于之前没有预留接口,导致没法进行扩展,出现需要修改原来的代码的情况:里氏代换原则:在软件系统中,一个可以接收基类(父类)对象的地方必然可以接收一个子类对象。其属于开闭原则的实现

设计模式之设计原则

相关设计原则图

微信图片_20221214030239.png

设计原则

下面我们来看它们的使用的相关场景:

1.单一职责原则

单一职责原则:类的职责单一,不能将太多的职责放在一个类中,该原则是实现高内聚、低耦合的指导方针

比如:进行登录操作需要经过用户请求、参数校验、查找用户、连接数据库、操作数据库等这些操作

publicclassLogin1 {
//登录,用户请求该方法publicStringlogin(Stringusername,Stringpassword){
Booleanbo=validate(username,password);   //参数校验Objectuser=findUser(username, password); //查找用户if(user==null){
return"登录失败";
        }
return"SUCCESS";
    }
//参数校验publicBooleanvalidate(Stringusername,Stringpassword){
returntrue;
    }
//查找用户信息publicObjectfindUser(Stringusername,Stringpassword){
returnnull;
    }
//链接数据库publicConnectiongetConn(){
returnnull;
    }
//操作数据库publicResultSetquery(){
returnnull;
    }
}

根据上面的职责单一原则,我们可以将其变成:

用户请求、数据查找、数据库连接、数据库操作等

publicclassLoginController {
@AutowiredprivateLoginServiceloginService;
//①登录,用户请求该方法publicStringlogin(Stringusername,Stringpassword){
Booleanbo=validate(username,password);   //参数校验Objectuser=loginService.findUser(username, password); //查找用户if(user==null){
return"登录失败";
        }
return"SUCCESS";
    }
//②参数校验publicBooleanvalidate(Stringusername,Stringpassword){
returntrue;
    }
}

数据查询业务

publicclassLoginService {
@AutowiredprivateLoginDaologinDao;
publicObjectfindUser(Stringusername, Stringpassword) {
returnloginDao.query();
    }
}

数据库操作:

publicclassLoginDao {
@AutowiredprivateDBUtildbUtil;
//查询数据库publicObjectquery() {
returndbUtil.getConn();
    }
}

数据库连接

publicclassDBUtil {
privateObjectconn;
publicObjectgetConn() {
returnconn;
    }
}

这个时候,我们就实现了不同的类做不同的事了。而不是一个类做所有的事。

2.开闭原则

开闭原则:一个软件应当对扩展开发、对修改关闭。即在不修改源代码的情况下改变对象的行为

比如:我们现在需要查看报表,但是由于之前没有预留接口,导致没法进行扩展,出现需要修改原来的代码的情况:

publicclassPieChart {
publicvoiddisplay(){
System.out.println("饼状报表展示");
    }
}

之后又加了一个柱状报表:

publicclassBarChart {
publicvoiddisplay(){
System.out.println("柱状报表展示");
    }
}

现在想进行饼状、柱状报表的查看,代码可能是这样的:

publicclassChartDisplay {
publicstaticvoidmain(String[] args) {
Scannersc=newScanner(System.in);
inti=sc.nextInt();
//输入1,则打印饼状报表if(i==1){
PieChartchart=newPieChart();
chart.display();
//输入2,则打印柱状报表        }elseif(i==2){
BarChartchart=newBarChart();
chart.display();
        }
    }
}

这个时候就不符合开闭原则了,这个时候首先想到的是给以后的更多的报表预留接口,这样方便后来的报表查看,编写一个接口,然后使用抽象类去继承,这里使用抽象类进行演示:

publicabstractclassAbstractChart {
abstractvoiddisplay();
}

进行继承操作

柱状报表:

publicclassBarChartextendsAbstractChart{
@Overridepublicvoiddisplay(){
System.out.println("柱状报表展示");
    }
}

饼状报表:

publicclassPieChartextendsAbstractChart{
@Overridepublicvoiddisplay(){
System.out.println("饼状报表展示");
    }
}

进行展示

publicclassChartDisplay {
privatestaticAbstractChartabstractChart;
publicstaticvoidmain(String[] args) throwsException {
Scannersc=newScanner(System.in);
StringclassName=sc.nextLine();
//根据输入的类名获取对应实例setAbstractChart(className);
//调用方法abstractChart.display();
    }
/**** 根据需要创建实例*/publicstaticvoidsetAbstractChart(StringclassName) throwsException {
abstractChart= (AbstractChart) Class.forName(className).newInstance();
    }
}

也即首先抽象出原始接口,在原始接口的基础之后进行扩展。

3.里氏代换原则

里氏代换原则:在软件系统中,一个可以接收基类(父类)对象的地方必然可以接收一个子类对象。其属于开闭原则的实现

给用户发消息:

publicclassCommonCustomer {
privateStringname;
privateStringphone;
publicCommonCustomer() {
    }
publicCommonCustomer(Stringname, Stringphone) {
this.name=name;
this.phone=phone;
    }
publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
publicStringgetPhone() {
returnphone;
    }
publicvoidsetPhone(Stringphone) {
this.phone=phone;
    }
publicStringsefInfo() {
return"给普通客户发消息,客户名字:"+name+",客户手机号:"+phone;
    }
}

vip用户:

publicclassVipCustomer {
privateStringname;
privateStringphone;
publicVipCustomer() {
    }
publicVipCustomer(Stringname, Stringphone) {
this.name=name;
this.phone=phone;
    }
publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
publicStringgetPhone() {
returnphone;
    }
publicvoidsetPhone(Stringphone) {
this.phone=phone;
    }
publicStringsefInfo() {
return"给VIP客户发消息,客户名字:"+name+",客户手机号:"+phone;
    }
}

发消息:

publicclassSendMessage {
publicstaticvoidmain(String[] args) {
CommonCustomercommonCustomer=newCommonCustomer("王五","13670001111");
VipCustomervipCustomer=newVipCustomer("赵六","13670001133");
send(vipCustomer);
send(commonCustomer);
    }
//给VIP客户发消息publicstaticvoidsend(VipCustomervipCustomer){
System.out.println(vipCustomer.sefInfo());
    }
//给普通客户发消息publicstaticvoidsend(CommonCustomercommonCustomer){
System.out.println(commonCustomer.sefInfo());
    }
}

从上面的代码我们可以抽象出公共的信息,同时对公共信息进行扩展,然后调用方法进行发消息

publicabstractclassCustomer {
privateStringname;
privateStringphone;
publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
publicStringgetPhone() {
returnphone;
    }
publicvoidsetPhone(Stringphone) {
this.phone=phone;
    }
publicabstractStringsefInfo();
}

进行公共行为扩展:

普通用户:

publicclassCommonCustomerextendsCustomer{
@OverridepublicStringsefInfo() {
return"给普通客户发消息,客户名字:"+super.getName() +",客户手机号:"+super.getPhone();
    }
}

vip用户

publicclassVipCustomerextendsCustomer {
@OverridepublicStringsefInfo() {
return"给VIP客户发消息,客户名字:"+super.getName() +",客户手机号:"+super.getPhone();
    }
}

进行发送操作:

publicabstractclassSendMessage {
publicstaticvoidmain(String[] args) {
CustomercommonCustomer=newCommonCustomer();
commonCustomer.setName("王五");
commonCustomer.setPhone("13670001111");
CustomervipCustomer=newVipCustomer();
vipCustomer.setName("赵六");
vipCustomer.setPhone("13670001155");
send(vipCustomer);
send(commonCustomer);
    }
//给VIP客户发消息publicstaticvoidsend(Customercustomer){
System.out.println(customer.sefInfo());
    }
}

同时在此基础上,我们可以进行对应的业务操作。

4.依赖倒转原则

依赖倒转原则:抽象不应该依赖细节实现,细节应当依赖抽象,也即面向接口编程,用到接口的地方,通过依赖注入将接口的实现对象注入进去。

抽象接口:

publicabstractclassAbstractChart {
abstractvoiddisplay();
}

进行继承:

publicclassBarChartextendsAbstractChart {
@Overridepublicvoiddisplay(){
System.out.println("柱状报表展示");
  }
}
publicclassPieChartextendsAbstractChart {
@Overridepublicvoiddisplay(){
System.out.println("饼状报表展示");
    }
}

进行展示:

publicclassChartDisplay {
privateAbstractChartabstractChart;
//展示报表publicvoidshowChart(){
abstractChart.display();
    }
//Setter注入publicvoidsetAbstractChart(AbstractChartabstractChart) {
this.abstractChart=abstractChart;
    }
}

5.接口隔离原则

接口隔离原则:不使用一个总接口,而使用多个接口进行隔离,即客户端不依赖它原本不需要调用的接口

使用一个总接口完成所有操作:

publicinterfaceDataRead {
//增删改查voidquery();
voidinsert();
voiddelete();
voidupdate();
//定时任务执行voidqueryTask();
voidcreateTask();
//报表voidreportExcel();
}

这是不符合接口隔离原则的,因此我们可以将增删查改放入一个接口,定时任务放入一个接口,报表放入一个接口

增删查改接口:

publicinterfaceCrudInterface {
//增删改查voidquery();
voidinsert();
voiddelete();
voidupdate();
}

定时任务接口:

publicinterfaceTaskInterface {
//定时任务执行voidqueryTask();
voidcreateTask();
}

报表接口:

publicinterfaceReportInterface {
//报表voidreportExcel();
}

6.合成/复用原则

合成/复用原则:尽量使用对象组合,而不是使用继承来达到复用的目的

publicclassBookDaoextendsMySQLUtil {
//查询publicResultSetquery() throwsException{
//获得数据库链接Connectionconn=super.getConn();
PreparedStatementps=conn.prepareStatement("select * from table");
returnps.executeQuery();
    }
}

如果数据源发生改变,此时就不能达到复用了,采用DBUtils,然后采用MysSQLUtils继承,进行注入,如果更换其他数据,注入即可。因此可以采用注入的放入,这样可以方便复用,工具类中,放入那个参数就使用哪个。

publicclassBookDao  {
@AutowiredprivateMySQLUtilmySQLUtil;
//查询publicResultSetquery() throwsException{
//获得数据库链接Connectionconn=mySQLUtil.getConn();
PreparedStatementps=conn.prepareStatement("select * from table");
returnps.executeQuery();
    }
}

7.迪米特原则

迪米特原则:一个软件实体应当尽可以少的和其他类发生相互作用,降低耦合度

publicclassOrderController {
privateGoodsDaogoodsDao;
privateOrderDaoorderDao;
privateLogDaologDao;
//添加订单publicvoidadd(){
//①修改库存goodsDao.modify();
//②增加订单orderDao.add();
//③记录日志logDao.recode();
    }
}

修改成:

商品信息操作:

publicclassGoodsController {
privateGoodsServicegoodsService;
publicvoidmodify(){
goodsService.modify();
    }
}

进行订单新增:

publicclassOrderController {
privateOrderServiceorderService;
//添加订单publicvoidadd(){
    }
}

logDao:

publicclassLogDao {
publicvoidrecode() {
System.out.println("记录日志!");
    }
}

也即不同的类进行不同的操作。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
设计模式 关系型数据库
【设计模式——学习笔记】设计模式简介+七大设计原则介绍(下)
【设计模式——学习笔记】设计模式简介+七大设计原则介绍
113 0
|
设计模式 前端开发 算法
设计模式之设计原则
程序设计的要遵循的一些理论,也可以理解为程序设计的一种要求和目标,是面向对象程序设计的基石,也是面向对象程序设计的质量保障和依据。
82 0
|
2月前
|
设计模式 Java 测试技术
Java设计模式-UML与设计原则(1)
Java设计模式-UML与设计原则(1)
|
3月前
|
设计模式 前端开发 JavaScript
React开发设计模式及原则概念问题之什么是HOC(Higher-order component),HOC遵循的设计原则都有哪些
React开发设计模式及原则概念问题之什么是HOC(Higher-order component),HOC遵循的设计原则都有哪些
|
4月前
|
设计模式 算法
交易链路设计原则&模式问题之中介者(Mediator)方法设计模式是什么,如何解决
交易链路设计原则&模式问题之中介者(Mediator)方法设计模式是什么,如何解决
|
6月前
|
设计模式 算法 Java
【设计模式系列笔记】设计模式与设计原则
设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 设计原则是一些通用的设计指导方针,它们提供了如何设计一个优秀的软件系统的基本思想和规则。指导着设计者如何组织代码以实现高内聚、低耦合、易扩展和易维护的软件系统。
81 4
|
设计模式 Java 关系型数据库
Java设计模式中的设计原则 2
Java设计模式中的设计原则
87 0
|
6月前
|
设计模式 Java 数据安全/隐私保护
设计模式之六大设计原则
设计模式之六大设计原则
69 0
|
6月前
|
设计模式 关系型数据库 程序员
【设计模式】设计原则
【1月更文挑战第12天】【设计模式】设计原则
|
设计模式 Java 程序员
【设计模式——学习笔记】设计模式简介+七大设计原则介绍(上)
【设计模式——学习笔记】设计模式简介+七大设计原则介绍
51 2

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    46
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    54
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    62
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    57
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    41
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    106
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78