solid设计原则_SOLID设计原则

solid设计原则

介绍:

Robert C. Martin定义了五项面向对象的设计原则:

  • 小号英格尔-责任原则
  • Ø笔封闭原则
  • 大号 iskov的替换原则
  • 覆盖整个院落分离原则,并
  • d ependency倒置原则

这些一起被普遍称为SOLID原则。 在设计面向对象的系统时,我们应尽可能遵循这些原则。 这些原则有助于我们设计一个更可扩展,可理解和可维护的系统。

随着应用程序规模的扩大,使用这些原则可以帮助我们节省很多工作。

单一责任原则:

顾名思义,“单一责任原则”(SRP)指出, 每个类都必须恰好要做一件事。 换句话说,我们修改类的原因不应多于一个。

众所周知,大型系统通常具有数千个类。 如果对于任何新要求,需要涉及多个类,那么我们就有更多的机会通过破坏另一种功能来引入错误。

单一责任原则为我们带来以下好处:

  • 更少的耦合:由于每个类都只会做一件事,因此依赖性将大大减少
  • 易于测试:更少的测试用例可以覆盖整个系统,从而使代码更易于测试

我们系统的模型类通常始终遵循SRP原则。 可以这么说,我们需要修改系统中用户的状态,我们只需触摸User类:

 public class User {  private int id; private String name; private List<Address> addresses;     //constructors, getters, setters  } 

因此,它遵循SRP原则。

开闭原理:

开放式封闭原则指出, 必须打开软件组件才能进行扩展,但必须关闭才能进行修改。 此处的目的是避免由于代码修改而破坏某些现有的工作功能,从而避免在系统中引入错误。 我们应该扩展现有的类以支持任何其他功能。

此规则适用于我们的系统中更稳定的类,这些类已通过测试阶段并且在生产中运行良好 。 我们将希望避免破坏现有代码中的任何内容,因此我们应该扩展其支持的功能以满足新的需求。

假设我们的系统中有一个EventPlanner类,该类在生产服务器上长期运行良好:

 public class EventPlanner {  private List<String> participants; private String organizer;  public void planEvent() { System.out.println( "Planning a simple traditional event" ); ... }  ...  } 

但是现在,我们计划改用ThemeEventPlanner ,它将使用随机主题来计划事件,以使事件更加有趣。 与其直接跳入现有代码并添加选择事件主题并使用它的逻辑,不如扩展我们的生产稳定类:

 public class ThemeEventPlanner extends EventPlanner { private String theme;  ...  } 

对于大型系统,确定类可能出于什么目的使用并不是很简单。 因此,仅通过扩展功能, 我们就减少了处理系统未知数的机会。

里斯科夫的替代原则:

Liskov的“替换原理”说, 派生类型必须能够完全替代其基本类型,而不改变现有行为。 因此,如果我们有两个类AB使得B扩展了A,那么我们应该能够在整个代码库中用B替换A而不影响系统的行为。

为了使我们能够实现这一点, 子类的对象的行为必须与超类对象的行为完全相同。

该原则有助于我们避免类型之间的错误关系,因为它们可能导致意外的错误或副作用。

让我们看下面的例子:

 public class Bird { public void fly() { System.out.println( "Bird is now flying" ); }  }   public class Ostrich extends Bird { @Override public void fly() { throw new IllegalStateException( "Ostrich can't fly" ); }  } 

尽管鸵鸟 ,但它仍然不会飞,因此这明显违反了Liskov替代原理(LSP)。 同样,涉及类型检查逻辑的代码清楚地表明已建立了不正确的关系。

重构代码以遵循LSP有两种方法:

  • 消除对象之间的错误关系
  • 使用“ 告诉,不要问 ”原理消除类型检查和转换

假设我们有一些涉及类型检查的代码:

 //main method code  for (User user : listOfUsers) { if (user SubscribedUser) { (user instanceof SubscribedUser) { user.offerDiscounts(); } user.makePurchases();  } 

使用“告诉,不要问”的原则,我们将重构上面的代码,使其看起来像:

 public class SubscribedUser extends User { @Override public void makePurchases() { this .offerDiscounts(); super .makePurchases(); }  public void offerDiscounts() {...}  }   //main method code  for (User user : listOfUsers) { user.makePurchases();  } 

接口隔离原理:

根据接口隔离原则, 不应强迫客户端处理不使用的方法。 我们应该在需要时将较大的接口拆分为较小的接口。

假设我们有一个ShoppingCart界面:

 public interface ShoppingCart {  void addItem(Item item); void removeItem(Item item); void makePayment(); boolean checkItemAvailability(Item item);     } 

付款和检查商品的可用性不是购物车要执行的操作。 我们很可能会遇到不使用这些方法的该接口的实现。

因此,最好将上述接口改为:

 public interface BaseShoppingCart { void addItem(Item item); void removeItem(Item item);  }   public interface PaymentProcessor { void makePayment();  }   public interface StockVerifier { boolean checkItemAvailability(Item item);  } 

接口隔离原则(ISP)还加强了其他原则:

  • 单一职责原则:实现较小接口的类通常更加集中并且通常具有单一目的
  • Liskov替换原理:使用较小的接口,我们有更多的机会让类实现它们以完全替代接口

依赖倒置:

它是最流行和有用的设计原则之一,因为它促进了对象之间的松散耦合。 依赖倒置原则指出高级模块不应该依赖于低级模块; 两者都应取决于抽象。

高级模块告诉我们该软件应该做什么 。 用户授权和付款是高级模块的示例。

另一方面, 低级模块告诉我们该软件应如何执行各种任务,即它涉及实现细节。 低级模块的一些示例包括安全性(OAuth),网络,数据库访问,IO等。

让我们编写一个UserRepository接口及其实现类:

 public interface UserRepository { List<User> findAllUsers();  }  public class UserRepository implements UserRepository {  public List<User> findAllUsers() { //queries database and returns a list of users ... }  } 

我们在这里提取了接口中模块的抽象。

现在说我们有高级模块UserAuthorization ,它检查用户是否被授权访问系统。 我们将仅使用UserRepository接口的引用:

 public class UserAuthorization {  ...  public boolean isValidUser(User user) { UserRepository repo = UserRepositoryFactory.create(); return repo.getAllUsers().stream().anyMatch(u -> u.equals(user)); }  } 

此外,我们使用工厂类来实例化UserRepository

请注意, 我们仅依靠抽象而不是依赖。 因此,我们可以轻松添加UserRepository的更多实现,而对我们的高级模块没有太大影响。

多么优雅!

结论:

在本教程中,我们讨论了SOLID设计原则。 我们还查看了上述每种原则的Java代码示例。

翻译自: https://www.javacodegeeks.com/2019/09/solid-design-principles.html

solid设计原则

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

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

相关文章

nosql简答什么是最终一致性_NoSql的三大基石:CAP理论BASE最终一致性

关系型数据库的局限NoSql出现在关系型数据库之后&#xff0c;主要是为了解决关系型数据库的短板&#xff0c;我们先来看看随着软件行业的发展&#xff0c;关系型数据库面临了哪些挑战&#xff1a;1、高并发一个最典型的就是电商网站&#xff0c;例如双11&#xff0c;几亿大军的…

二叉树的先中后序遍历

【0】README 0.1&#xff09;本文旨在理清二叉树的先中后序遍历&#xff0c; 以及如何建立二叉树等相关内容&#xff1b; 0.2&#xff09;本文涉及代码均为原创&#xff1b; 0.3&#xff09;本文中遍历后的打印结果&#xff0c;朋友您可以直接写出二叉树的节点构造出来&…

表达式树

【0】README 0.1&#xff09;本文旨在总结出表达式树的构建步骤&#xff0c; 其中还涉及到中缀转后缀表达式&#xff0c;以及如何计算 表达式树中的值&#xff1b; 0.2&#xff09;本文源代码均为原创&#xff1b; 0.3&#xff09; 其实&#xff0c; 实现一个简单的计算器&a…

Date/Timestamp/String/LocalDate/LocalDateTime

文章目录String 转成 DateDate 转成 StringString 转成 Timestamp获取系统当前的毫秒数获取系统当前的日期时间毫秒数转成 Timestamp毫秒数转成 DateTimestamp 转成 StringDate 转成 TimestampTimestamp 转成 Datejava.util.Date 转成 java.sql.Date将带T的日期时间转成正常的日…

python可以用来写什么工具_python写工具

谷歌开源 Python Fire&#xff1a;可自动生成命令行接口今天我们很高兴地宣布 Python Fire 开源。Python Fire 可从任何 Python 代码生成命令行接口(command line interfaces (CLIs))&#xff0c;简单地调用任意 Python 程序中的 Fire 函数以将那个程序自动地转化为 CLI。该库可…

java原始类型和引用类型_Java中的8种原始类型

java原始类型和引用类型几年前&#xff0c;当我开始编辑Java Basics系列时&#xff0c;我认为将一些非常详细的信息拉到自己的帖子中是很有意义的。 这样&#xff0c;初学者的内容就更容易消化了。 首先&#xff0c;我将介绍有关Java的8种原始类型的所有信息。 Java基本类型 正…

androidtabhost缓存_FragmentTabHost布局的使用及优化方式

欢迎Follow我的GitHub, 关注我的简书. 其余参考Android目录.TabHostAndroidFragmentTabHost作为Android4.0版本的控件, 已经被项目广泛使用, 5.0版本又推出TabLayoutViewPager显示多页. 我来讲解如何使用FragmentTabHost.本文源码的GitHub下载地址主要包括:(1) 自定义Tab的图片…

二叉查找树

【0】README 0.1&#xff09;本文的重点在于介绍 二叉查找树的概念&#xff0c;以及写出 二叉查找树的操作例程的源代码&#xff0c; 其中当属delete 操作的源代码最不容易实现&#xff1b; 0.2&#xff09;本文源代码均为原创&#xff0c; 当然 代码中的idea 是借鉴人家的&a…

常用的命名规范/命名规则

文章目录骆驼式命名法&#xff08;CamelCase&#xff09;帕斯卡命名法&#xff08;PascalCase&#xff09;串式命名法&#xff08;KebabCase&#xff09;下划线命名法&#xff08;UnderScoreCase&#xff09;骆驼式命名法&#xff08;CamelCase&#xff09; 也叫小驼峰式命名法…

spring order_Spring @Order批注

spring order介绍&#xff1a; Spring Order注释是在Spring 2.0中首次引入的。 然后&#xff0c;它仅用于定义AspectJ建议中的顺序。 在Spring 4.0的后面&#xff0c;对该注释的实现进行了进一步改进。 从那时起&#xff0c;它还支持对Java数组或List之类的集合中的Spring组件或…

AVL树

【0】README 0.1&#xff09;本文给出了平衡二叉树&#xff08;AVL树&#xff09;的插入例程涉及到的单旋转双旋转的概念&#xff0c;并给出了代码实现&#xff1b; 0.2&#xff09;本文源代码均为原创&#xff0c; 当然相关idea 还是借鉴人家的&#xff1b;&#xff08;真心…

spring 注释_Spring@懒惰注释

spring 注释介绍&#xff1a; 默认情况下&#xff0c; Spring框架在应用程序启动时加载并热切初始化所有bean。 在我们的应用程序中&#xff0c;我们可能有一些非常消耗资源的bean。 我们宁愿根据需要加载此类bean。 我们可以使用Spring Lazy批注实现此目的 。 在本教程中&…

管理系统的账户设计(涉及注册/登录逻辑)

文章目录方案一方案二方案三方案一 类似华为云IAM&#xff08;Identity and Access Management 身份和访问管理&#xff09;用户&#xff0c;阿里云的 RAM&#xff08;Resource Access Management 资源访问管理&#xff09;用户 机构有独立的账户&#xff08;主账户&#xff…

opencv生成日志_OpenCV-Utils学习日志:VideoCapture使用样例

1.VideoCapture可以打开多种来源的数据流&#xff0c;但常见的是相机、视频及图像序列三类数据流&#xff1a;(1)打开相机数据流&#xff0c;需要指定相机在主机上的设备编号&#xff0c;若主机上只有一个相机则编号通常是0。(2)打开视频数据流&#xff0c;需要指定视频的完整路…

jdbc查询序列_JDBC –模拟序列

jdbc查询序列也许我们每个人在程序员的生活中至少遇到过一次这个问题- 如何模拟数据库序列&#xff1f; 在下面&#xff0c;您可能会发现我对该问题解决方案的各种了解。 假设我们有一个接口定义了所需的API&#xff0c;用于返回整数序列&#xff1a; public interface Sequen…

利用 GregorianCalendar 制作当前月的月历

【0】README 0.1&#xff09;本文文字总结于 core java volume 1 &#xff0c; 源代码均为原创&#xff1b; 0.2&#xff09;本文旨在熟悉 GregorianCalendar 日历类&#xff0c;每一天就是一个GregorianCalendar 日历类&#xff0c;一天有很多的日历属性&#xff0c;觉得用它…

pyecharts怎么绘制散点图_PyeCharts绘制各种图形

简介PyeCharts 是一个用于生成 Echarts 图表的类库&#xff0c;用其生成的图可视化效果非常棒&#xff0c;而且使用起来非常简单。下面是一些常用图的pyecharts实现方法柱状图bar pye.Bar("柱状图")#新建柱状图bar.add("服装", #图例名称["衬衫"…

junit junit_穿越JUnit流

junit junit关于JUnit 5迁移的好处之一是&#xff0c;您可以在老式模式下运行JUnit 4测试&#xff0c;并且所有内容仍然兼容。 不利的一面是&#xff0c;某些注释和方法在JUnit 4和JUnit 5中具有相同的名称&#xff0c;并且当两组库依赖项都可用时&#xff0c;很容易导入错误的…

被遗忘的软件产品形态

从2010年以后&#xff0c;很多公司开发的软件产品&#xff0c;很少有客户端了&#xff0c;web2.0之后&#xff0c;主流的业务系统基本上都是基于Web去构建业务系统。这几年见到的业务应用系统都是基于Web的构建的。而在To C市场&#xff0c;几乎就没有客户端了&#xff0c;都是…

vue进行判断使用class_vue判断dom的class

vue点击给dom添加class然后获取含有class的dom{{item.name}}{{item2.name}}jschek(index2, index) {this.iac[index2] indexthis.iac this.iac.concat([]);this.checkchose()},checkchose:function(){var chosethisvar chosedomchose.$refs.choseboxconsole.log(chosedom)for…