导语

在之前完成基于UDP的通信项目时,用到了设计模式中的单例模式。在写事件的监听器时,也了解到了观察者模式。

于是乎,我对于设计模式想要有一个系统的了解,也希望能够实际运用好合适的设计模式,来实现代码的低耦合、高复用。

设计模式是什么

首先,什么是设计模式呢?

它是一套被反复使用多数人知晓的经过分类的代码设计经验的总结,相当于某种约定俗成的规则。使用设计模式可以令代码真正地实现工程化。

项目中,合理运用设计模式可以完美地解决很多问题。因为每种设计模式都是为了解决我们经常遇到的某种问题,也有实际的原理与之对应。

我们之所以提倡使用设计模式,是为了实现代码复用增加可维护性

设计模式的六大原则

设计模式的原则其实来源于面向对象编程的原则,总的来说,是:

对接口编程而不是对实现编程。
优先使用对象组合而不是继承。

开闭原则

开闭原则(Open Close Principle),是指对扩展开放,对修改关闭

意思是说,在代码需要扩展时,能够不修改原有的代码。

要实现这一原则,关键的步骤就是抽象化。接口和抽象类的使用可以帮助我们实现抽象化。

比如:我们可以编写student接口,包含study的接口方法。
而当我们实际使用时,如果需要大学生,就直接写一个大学生类college_student实现student接口,就可以进行扩展;需要小学生,就写一个小学生类pupil来实现student接口。而不必修改之前写好的代码。

里氏代换原则

里氏代换原则(Liskov Substitution Principle)是指,任何子类都可以出现在其基类出现的地方,也可以替换掉基类,并且软件单元的功能不受影响。

这是对开闭原则的补充。因为开闭原则是说要实现抽象化,而里氏代换则是指出了实现抽象化的具体步骤的规范。

所以要求:

  • 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
  • 子类中可以增加自己特有的方法。
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

通俗一点说,里氏代换原则要求子类比父类更加宽松。

依赖倒转原则

依赖倒转原则(Dependence Inversion Principle)的定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。核心思想是指:针对接口编程,依赖于抽象而不依赖于具体

比如顾客类customer有一个shopping方法,该方法的形参是youyishop类的对象,表示该顾客去友谊商店购物。
如果我们想修改需求,要表示该顾客去步步高商城购物,就要修改customer类的shopping方法的形参,改为bubugaoshop类的对象。
这显然是不符合我们面向对象设计的原则的。
.
所以在编写customer类的shopping方法时,不应该让它依赖youyishop类或者bubugaoshop类,而应该让它依赖shop接口。
这样,我们在后续的商店变动过程中,就不需要修改原有的代码,只需要增加新的代码去实现shop接口。

接口隔离原则

接口隔离原则(Interface Segregation Principle)和面向对象编程中的单一职责原则是相辅相成的。也就是说,使用多个隔离的接口,比使用单个含有不同接口方法的接口要好

所以,我们要做的就是 为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用

这样一来,当一个类实现接口时,就不用实现其不需要的接口方法。
这样可以降低类之间的耦合度。

尽管接口隔离原则单一职责原则都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两者是不同的:

  • 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。
  • 单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。

迪米特原则

迪米特原则(Demeter Principle)也叫最小知道原则,是指一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相互独立
其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。

比如说我在之前写UDP通信的项目时,应该将收发消息的通信模块和处理消息的模块分隔开,不应直接互相调用。这样比较便于代码的修改与维护。

下图也是一个很好的例子。明星和粉丝、媒体公司之间尽量少地相互作用,而是通过经纪人进行处理。
设计模式的总览与分类

合成复用原则

合成复用原则(Composite Reuse Principle)是指:尽量使用合成/聚合的方式,而不是使用继承

这是基于类的复用来讲的。
我们知道类的复用一般分为继承复用和合成复用两种:

继承复用:

  • 简单、易实现
  • 破坏类的封装性(将父类细节暴露给了子类),又叫“白箱复用
  • 父类、子类之间耦合度高,父类的任何改变也会导致子类的改变,不利于类的拓展和维护
  • 限制了复用的灵活性。因为继承是静态的,编译时已经定义。

合成复用:

  • 维持了类的封装性,又叫“黑箱复用
  • 新旧类之间耦合度低。复用所需依赖较少,新对象存取成分对象的唯一方法是通过成分对象的接口。
  • 复用的灵活性高。可以在运行时动态进行,新对象可以动态引用与成分对象类型相同的对象。

继承复用的例子:
设计模式的总览与分类
合成复用的例子:
设计模式的总览与分类

23种经典设计模式

创建型模式(5种)

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

  • 工厂模式(Factory Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 单例模式(Singleton Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)

结构型模式(7种/8种)

这些设计模式关注类和对象的组合。继承的概念被用来组合接口定义组合对象获得新功能的方式。

  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 过滤器模式(Filter、Criteria Pattern)
  • 组合模式(Composite Pattern)
  • 装饰器模式(Decorator Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)

行为型模式(11种/12种)

这些设计模式特别关注对象之间的通信

  • 责任链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 解释器模式(Interpreter Pattern)
  • 迭代器模式(Iterator Pattern)
  • 中介者模式(Mediator Pattern)
  • 备忘录模式(Memento Pattern)
  • 观察者模式(Observer Pattern)
  • 状态模式(State Pattern)
  • 空对象模式(Null Object Pattern)
  • 策略模式(Strategy Pattern)
  • 模板模式(Template Pattern)
  • 访问者模式(Visitor Pattern)

J2EE模式(8种)

这些设计模式特别关注表现层。这些模式是由Sun Java Center鉴定的。

  • MVC模式(MVC Pattern)
  • 业务代表模式(Business Delegate Pattern)
  • 组合实体模式(Composite Entity Pattern)
  • 数据访问对象模式(Data Access Object Pattern)
  • 前端控制器模式(Front Controller Pattern)
  • 拦截过滤器模式(Intercepting Filter Pattern)
  • 服务定位器模式(Service Locator Pattern)
  • 传输对象模式(Transfer Object Pattern)

结束语

本篇博客主要记录了自己对设计模式的六大原则的理解。

依我之见,设计模式其实是一些降低代码耦合度、提高代码复用性的方案。而六大原则的目的也是如此。

开闭原则告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。

而对于23种设计模式,仅仅是列举了一下。将会在以后的学习中深入理解,并且总结成学习博客。

相关文章: