开闭原则(Open Closed Principle)

定义:软件实体应该对扩展开放,对修改关闭。

其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。

软件实体:项目或软件产品中按照一定的逻辑规则划分的模块、抽象和类、方法。

变化的三种类型:

  • 逻辑变化 只变化一个逻辑,而不涉及其他模块,比如原有的一个算法是ab+c,现在需要修改为ab*c,可以通过修改原有类中的方法的方式来完成,前提条件是所有依赖或关联类都按照相同的逻辑处理
  • 子模块变化 一个模块变化,会对其他的模块产生影响,特别是一个低层次的模块变化必然引起高层模块的变化,因此在通过扩展完成变化时,高层次的模块修改是必然的
  • 可见视图变化 可见视图是提供给客户使用的界面,如JSP程序、Swing界面等,该部分的变化一般会引起连锁反应(特别是在国内做项目,做欧美的外包项目一般不会影响太大)。可以通过扩展来完成变化,这要看我们原有的设计是否灵活

    Read More

依赖倒置原则(Dependence Inversion Principle)

原始定义:

  • 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
  • 抽象不应该依赖细节(实现类);
  • 细节应该依赖抽象。

依赖倒置原则在java语言中的体现:

  • 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
  • 接口或抽象类不依赖于实现类;
  • 实现类依赖接口或抽象类

依赖的三种写法:

  • 构造函数传递依赖对象(构造函数注入)
  • Setter方法传递依赖对象(setter依赖注入)
  • 接口声明依赖对象(接口注入)

使用原则:依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合,我们怎么在项目中使用这个规则呢?只要遵循以下的几个规则就可以:

  • 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备
  • 变量的表面类型尽量是接口或者是抽象类
  • 任何类都不应该从具体类派生(只要不超过两层的继承是可以忍受的)
  • 尽量不要复写基类的方法
  • 结合里氏替换原则使用

    Read More

接口隔离原则(Interface Segregation Principle)

接口分为两种:

  • 实例接口(ObjectInterface):Java中的类也是一种接口
  • 类接口(ClassInterface):Java中经常使用Interface关键字定义的接口

隔离:建立单一接口,不要建立臃肿庞大的接口;即接口要尽量细化,同时接口中的方法要尽量少。

接口隔离原则与单一职责原则的不同:接口隔离原则与单一职责的审视角度是不相同的,单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求接口的方法尽量少

Read More

里氏替换原则

定义:Functionsthatusepointersorreferencestobaseclassesmustbeabletouseobjectsofderivedclasseswithoutknowingit.(所有引用基类的地方必须能透明地使用其子类的对象。)

通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。

但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

定义中包含的四层含义:

  1. 子类必须完全实现父类的方法
  2. 子类可以有自己的个性
  3. 覆盖或实现父类的方法时输入参数可以被放大
  4. 覆写或实现父类的方法时输出结果可以被缩小

    Read More

单一职责原则(Single Responsibility Principle)

单一职责原则有什么好处:

  • 类的复杂性降低,实现什么职责都有清晰明确的定义;
  • 可读性提高,复杂性降低,那当然可读性提高了;
  • 可维护性提高,可读性提高,那当然更容易维护了;
  • 变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。

ps:接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。

单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异

Read More

门面模式(Facade Pattern)

定义:Provideaunifiedinterfacetoasetofinterfacesinasubsystem.Facadedefinesahigher-levelinterfacethatmakesthesubsystemeasiertouse.(要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。)

Facade门面角色

客户端可以调用这个角色的方法。此角色知晓子系统的所有功能和责任。一般情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去,也就说该角色没有实际的业务逻辑,只是一个委托类。

subsystem子系统角色

可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。子系统并不知道门面的存在。对于子系统而言,门面仅仅是另外一个客户端而已。

使用场景:

  • 为一个复杂的模块或子系统提供一个供外界访问的接口
  • 子系统相对独立——外界对子系统的访问只要黑箱操作即可
  • 预防低水平人员带来的风险扩散

注意:一个子系统可以有多个门面,门面不参与子系统内的业务逻辑

Read More

观察者模式(Observer Pattern)

定义:Defineaone-to-manydependencybetweenobjectssothatwhenoneobjectchangesstate,allitsdependentsarenotifiedandupdatedautomatically.(定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。)

Subject被观察者

定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。

Observer观察者

观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。

ConcreteSubject具体的被观察者

定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

ConcreteObserver具体的观察者

每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑

Read More

组合模式(Composite Pattern)

定义:Composeobjectsintotreestructurestorepresentpart-wholehierarchies.Compositeletsclientstreatindividualobjectsandcompositionsofobjectsuniformly.(将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。)

Component抽象构件角色

定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性,比如我们例子中的getInfo就封装到了抽象类中。

Leaf叶子构件

叶子对象,其下再也没有其他的分支,也就是遍历的最小单位

Composite树枝构件

树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构

使用场景:

  • 维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理。
  • 从一个整体中能够独立出部分模块或功能的场景。

注意:只要是树形结构,就考虑使用组合模式

Read More

迭代器模式(IteratorPattern)

定义:Provideawaytoaccesstheelementsofanaggregateobjectsequentiallywithoutexposingitsunderlyingrepresentation.(它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。)

Iterator抽象迭代器

抽象迭代器负责定义访问和遍历元素的接口,而且基本上是有固定的3个方法:first()获得第一个元素,next()访问下一个元素,isDone()是否已经访问到底部(Java叫做hasNext()方法)。

ConcreteIterator具体迭代器

具体迭代器角色要实现迭代器接口,完成容器元素的遍历。

Aggregate抽象容器

容器角色负责提供创建具体迭代器角色的接口,必然提供一个类似createIterator()这样的方法,在Java中一般是iterator()方法。

ConcreteAggregate具体容器

具体容器实现容器接口定义的方法,创建出容纳迭代器的对象。ps:迭代器模式已经被淘汰,java中已经把迭代器运用到各个聚集类(collection)中了,使用java自带的迭代器就已经满足我们的需求了

Read More