类设计的SOLID原则

SOLID原则是面向对象范式的核心

  1. 单一职责原则(Single Responsible Principle, SRP):对于一个类,应该仅有一个引起它变化的原因。其基础是内聚,表示类完成单一功能的程度。
  2. 开放—封闭原则(Open Closed Principle,OCP):类应该对扩展开放,对修改关闭。是SOLID原则中最重要的一个。OCP 的一个原则就是将类之间的耦合到抽象级别。
  3. Liskov替换原则(Liskov Substitution Principle,LSP):子类型应该能够替换它们的基类型。为了使用LSP,必须要遵循OCP ,违反了LSP 同时也就会违反OCP ,但反过来并不成立。OCP 的关注焦点是抽象耦合, 而LSP 尽管也很依赖抽象耦合,但它还严重依赖前置条件(precondition)和后置条件(postcondition)。前置条件是指方法调用前必须要满足的契约,后置条件在方法完成是必须为真。如果前置条件不满足,方法不应该调用;如果后置条件不满足,方法不应该返回。
  4. 依赖倒置原则(Dependency Inversion Principle,DIP):依赖抽象体,不要依赖固定的类。
  5. 接口隔离原则(Interface Segregation Principle, ISP):众多的接口要优于单一的、通用性的接口。
  6. 组合重用原则(Composite Reuse Principle,CRP):优先选择对象的多态组合而不是继承。

模块内聚

  高内聚的模块更易于理解、维护和重用。内聚是一个定性的测量,很难进行客观的评定。

  在软件开发中会根据变化频率和重用间关系进行打包,在开发生命周期的早期,系统不稳定而且变化很多,此时应该基于变化的频率打包而不是根据重用打包。当系统逐渐稳定后,再关注基于重用打包,此时变化少得多。

物理分层

  最常见的分层模式为展现、业务逻辑以及数据访问三层。但是每个分层中可能会有多个等级。

  展现层负责构造和渲染用户界面。业务逻辑或领域层包含业务对象,而数据访问层会封装持久化的数据存储以及外部系统的访问。

发布接口

  接口要更接近使用它们的类,

  发布接口是由导出包中公开类的公开方法组成的,它可以被其他的模块调用。

  使用标准的JAVA,阻止外部类访问你不想公开的类或方法的最简单方式就是使用接口。接口定义了想暴露的方法,而模块中的实现可以定义其他的公开方法。模块的用户应该使用接口进行交互,而不是使用实现。如果不使用转型,模块的用户将不能调用实现类中的方法。

外部配置

  外部化配置增加了模块的可重用性,但是降低了可用性。针对环境上下文配置模块方式多种:

  1. 配置信息包含在模块中:优势是在模块的默认上下文中很易于使用,不足在于这个默认配置很可能在其他的上下文中不能正常工作。
  2. 配置文件没有部署在模块中,但在初始化的时候将它提供给了模块:优势在于模块不再与它的上下文相耦合并且能够跨上下文重用。但是模块每次用于新环境时,必须要提供配置信息。

模块门面

  借助模块门面,可以保持一种平衡,也就是创建高重用性的细粒度和轻量级模块,同时又能为开发人员提供便利的方式使用这一组模块。但模块门面所增加的依赖会加大部署相关的复杂性。

抽象化模块

  通过在新的模块中,定义新的类来实现或扩展抽象体,能够更容易地扩展和维护应用。只依赖模块的抽象元素会付出一定的代价:创建实现类的实例时不能再使用new关键字了。作为替代,有如下方案:

  1. 对象工厂(object factory):可以避免依赖模块中具体元素。首先,工厂是应用中唯一引用具体类的地方,添加新的具体类来扩展抽象体会很容易;其次,如果有一些与创建实例相关的规则,那么这些规则就会被封装在工厂中,如果规则发生变化,只需维护一个地方。
  2. 动态创建(dynamic creation):某些情况下,使用Class类比对象工厂更合适。如下场景下会更好:第一种,在Web应用程序中,如果想在服务器启动的时候创建一些特定的类,可以使用Class类并且在启动属性文件中指定要实例化的具体类,通过指定新的类并将其全限定名设置在适当的属性文件中,这样就能够在服务器启动的时候,创建新的类并将其插入应用中;第二种,当使用抽象工厂模式(GOF)时,对于指定如何创建具体的工厂来说,将其指定在属性文件中也是很有用处的。在大多数的场景下,使用对象工厂方式比较多,但也有很多依赖注入框架,如Spring。
  3. OSGi uService:OSGi框架中,在OSGi bundle 启动的时候,uService 能够动态实例化那些注册为uService 服务的类。

分离抽象模式

  分离抽象有助于消除模块关系。但是,也会导致要管理更复杂的结构,使用分离抽象时,会面临灵活性和复杂性之间的取舍。通用指导原则如下:

  1. 如果依赖抽象体的所有类都在同一个模块中,那么将这些类与抽象体放在同一个模块中。
  2. 如果依赖抽象体的所有类位于多个模块中,那么将抽象体放在一个单独的模块中,这个模块与依赖抽象体的类实现了分离。包含实现的模块要依赖包含抽象体的模块。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户画像

逻辑覆盖 测试题

(2)  简述什么是测试用例。白盒测试的动态测试要根据程序的控制结构设计测试用例简述其原则。

482
来自专栏架构师之旅

轻松学习设计模式之面向对象的设计原则

对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决...

763
来自专栏字根中文校对软件

StreamCQL : 实时计算系统 ( CEP ) 中的持续查询语言 CQL

StreamCQL : 实时计算系统中的持续查询语言 CQL  ( Continuous Query Language )  是一个针对流式数据的查询语言。相对...

2664
来自专栏恰同学骚年

设计模式的征途—6.建造者(Builder)模式

建造者模式又称为生成器模式,它是一种较为复杂、使用频率也相对较低的创建型模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。因为...

1244
来自专栏向治洪

android性能优化

前言 性能优化本身是一个很大的主题,涵盖程序的方方面面,任何不慎的操作,都有可能对性能造成比较大的影响,要知道程序的性能是可以累加的,多处的性能低下,会影响整体...

1885
来自专栏微服务生态

由学习《软件设计重构》所想到的代码review(一)

对于一个程序员来讲如何来最直接的来衡量他的技术能力和产出呢?我想最直观的作法是看他的代码编写能力,就拿我经常接触的一些程序员来看,他们买了很多技术重构类书籍,但...

563
来自专栏互联网大杂烩

6大设计原则

所有引用基类的地方必须能透明地使用其子类对象。 只要父类能出现的地方子类就可以出现。

733
来自专栏JavaQ

Java中的各种O

Java中数据的封装会被命名为各种O,常见的有PO、VO、DTO、BO、POJO。 1.PO PO是Persistan...

3035
来自专栏开源优测

RobotFramework怎么写好用例

github地址:https://github.com/robotframework/HowToWriteGoodTestCases/blob/master/H...

452
来自专栏大数据和云计算技术

Codegen技术学习

Codegen在spark中的应用 除了前面查询优化中讲到逻辑优化器之外,Spark在1.5版本中引入了比较大的一个动作就是DataFrame执行后端的优化,引...

3685

扫码关注云+社区