目录
前言
编程思想中,入门心法就是面向对象思想,而最高心法就是设计模式思想。如果你能够参悟明白设计模式,并且能熟练掌握灵活运用它们,那你读各种库源码的时候会忽然发现并不难懂了。设计模式追求的目的就是“高内聚、低耦合”,在实际编程中运用设计模式能够使我们工程代码更规范、重用性更高,同时也能保证代码的可靠性、提高开发效率。
一、概述
面向对象编程有七大原则,即经常提到的设计模式(Design Pattern),提倡它的根本原因是为了代码复用,增加可维护性。设计模式就是实现了这些原则,从而达到了代码复用、增加可维护性的目的。
设计模式是继面向对象思想提升的更高级编程思想,分为三类 :创建型、结构型、行为型 。常用的有如下:1、创建型是为了隐藏类的创建,不再直接 new 对象实例。例如,单例模式、工厂模式、建造者模式。2、结构型是为了隐藏调用对象的方法,不再直接访问对象实例。例如,代理模式、适配器模式、装饰者模式。3、行为型是为了优化对象与对象之间一对多调用关系。例如,观察者模式、中介者模式、访问者模式。
二、7个设计原则
1、单一职责原则 ( SRP )
SRP(Single Responsibility Principle),表示,定义是一个类应该只有一个引起它变化的原因。类变化的原因就是职责,如果一个类承担的职责过多,就等于把这些职责耦合在一起了。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。而如果想要避免这种现象的发生,就要尽可能的遵守单一职责原则。此原则的核心就是解耦和增强内聚性。
2、开闭原则 ( OCP )
OCP(Open Close Principle),定义是软件实体(包括类、模块、函数等)应该对于扩展时开放的,对于修改是封闭的。开闭原则是是面向对象设计中最重要的原则之一,其它很多的设计原则都是实现开闭原则的一种手段。
3、里氏替换原则 ( LSP )
LSP(Liskov Substitution Principle) ,是面向对象设计的基本原则之一。 定义是任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏替换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。
4、依赖倒置原则 ( DIP )
DIP (Dependence Inversion Principle) ,这个原则是开闭原则的基础,依赖倒置原则就是要求调用者和被调用者都依赖抽象,这样两者没有直接的关联和接触,在变动的时候,一方的变动不会影响另一方的变动。依赖倒置强调了抽象的重要性,针对接口编程,依赖于抽象而不依赖于具体。
5、接口隔离原则 ( ISP )
ISP(Interface Segregation Principle) ,这个原则的意思是使用多个隔离的接口,比使用单个接口要好。目的就是降低类之间的耦合度,便于软件升级和维护。
6、最少知道原则(迪米特原则)
一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。通俗地说就是不要和陌生人说话,即一个对象应对其他对象有尽可能少的了解。迪米特法则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。
7、合成/聚合复用(CARP)
CARP(Composite Reuse Principle) ,合成/聚合复用原则经常又叫做合成复用原则。合成/聚合复用原则的潜台词是:我只是用你的方法,我们不一定是同类。继承的耦合性更大,比如一个父类后来添加实现一个接口或者去掉一个接口,那子类可能会遭到毁灭性的编译错误,但如果只是组合聚合,只是引用类的方法,就不会有这种巨大的风险,同时也实现了复用。
三、创建型模式 ( 5种 )
创建型模式是指这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用新的运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
1.单例模式
- 定义
确保某一个类只有一个实例,并自行实例化向整个系统提供这个实例。
- 简介
单例模式理解起来不难,典型例子有一个公司只能有一个CEO。它主要是为了保证一个类仅有一个实例,这个类中自己提供一个返回实例的方法,方法中先判断系统是否已经有这个单例,如果有则返回,如果没有则创建。如果创建多个实例会消耗过多的资源或者某种类型的对象只应该有且只有一个时,应该考虑使用单例模式。
- 实现
单例模式理解起来不难,重要的是需要掌握它的几种常见写法。
写法一、懒汉式写法
public class Singleton {
private static Singleton instance;
//构造函数私有
private Singleton (){
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
写法二、DCL(Double Check Lock) 双重校验锁
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){
}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
写法三、静态内部类单例模式
public class Singleton {
private Singleton (){
}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
}
上面只列出了单例模式常见的三种写法,单例模式还有好几种别的写法,这里就不全部列出了。上面的第一种懒汉式写法做到了延迟创建和线程安全,缺点是每次调用getInstance()时都必须进行同步,效率不佳。第二种DCL方式比较常见,两次判空,第一次判空避免了不必要的同步,第二次保证了单例创建,这种方式比较不错,但是在高并发环境下有时会出现问题。第三种方法最被推荐,线程安全也保证了实例唯一。
2.工厂方法模式
- 定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。
- 举例
工厂方法模式的典型例子,自行车分为山地自行车和公路自行车等,当需要买自行车时,我们直接去自行车厂里告诉厂长我们需要的自行车即可。
- 例子
1、定义一个接口自行车,Bike。
public interface Bike{
void ride();
}
2、定义实现类山地自行车,MBike
public class MBike implements Bike{
@Override
public void draw() {
System.out.println("MBike Rides... ");
}
}
3、定义实现类公路自行车,RBike
public