一、什么是设计模式
设计模式指软件开发过程中面临的一般问题的解决方案。
作用:更好的重用代码、可读性提高、保证代码可靠性 。
二、设计模式的六大原则
1、开闭原则(Open Close Principle)
一个软件实体(类、方法、模块),应该对扩展开放,对修改关闭。软件需要变化,尽量通过扩展软件实体的方式来完成,而不是通过修改原有代码来完成。
开闭原则是设计原则中的核心原则。
2、里氏代换原则(Liskov Substitution Principle)
子类能够完全替换父类出现的地方,并且经过替换后,不会改变原有的行为 。
3、依赖倒置原则(Dependence Inversion Principle)
高层模块不应该依赖底层模块,二者都依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象
4、接口隔离原则(Interface Segregation Principle)
使用专门的接口比用统一接口好,便于项目的组织和分工。不要让开发者面对用不到的方法。
5、迪米特法则(Demeter Principle)
一个对象应该对其他对象保持最少的了解,要很好的封装类,仅向外部暴露你提供的服务,内部的细节不需要让外界知道。
6、聚合/组合原则(Composite Reuse Principle)
尽可能使用聚合/组合的方式,而不是使用继承来达到代码的复用 。
三、设计模式的三大分类
1、创建模式(5种)
创建模式是一种创建型的设计模式 。
工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
A、单例模式(Singleton)
无论使用该类方法多少次,都只产生一个该类对象,可以减少系统内存的消耗 。
1.立即加载的单例模式--饿汉模式
缺点:类加载时,会直接实例化单例对象,不管我有没有使用到该单例对象,浪费内存 。
优点:没有加锁,执行效率高,线程安全的实例。
2 .延迟加载的单例模式--懒汉模式
//延迟加载的单例模式--懒汉模式
public class LazySingleton {
private LazySingleton(){}
private volatile static LazySingleton singleton;
/* 实例 会在调用getInstance方法时创建 线程不安全的
安全 单线程情况下,是安全的,但是在多线程下,
多个线程可能同时执行singleton == null都为true,
会创建多个实例在内存中
*/
public static LazySingleton getInstance(){
if(singleton == null){
singleton = new LazySingleton();
}
return singleton;
}
/* 线程安全的 但是效率低 需要同步,仅在第一次调用初始化时
锁的粒度太大,影响了程序的执行效率*/
public static synchronized LazySingleton getInstance(){
if(singleton == null){
singleton = new LazySingleton();
}
return singleton;
}
/* 双重检验 首先先判断实例是否为null,
为null则使用synchronized锁住类 ,
然后在同步块中,再一次判断实例是否为null,为null则初始化实例
synchronized(需要锁的对象){}
*/
public static LazySingleton getInstance(){
if(singleton == null){// 判断对象是否被初始化
// 对象没有被初始化,则加上类锁
synchronized (LazySingleton.class){
// 同时只有一个线程能够到这里
if(singleton == null){
// 创建实例对象
singleton = new LazySingleton();
}
}
}
// 实例对象的引用
return singleton;
}
}
优点:不会占用内存 。
缺点:安全 单线程情况下,是安全的,但是在多线程下,多个线程可能同时执行singleton == null 都为true,会创建多个实例在内存中
3. 静态内部类--创建单例模式
在外部类加载时,并不会加载内部类,也就是不会执行new 实例(),这属于懒加载 ,只有第一次调用getInstance方法时,才会加载。
4.枚举创建单例模式
实现单例的最佳方法。简洁,自持自动序列化机制,防止多次实例化 但是目前还没有被广泛采用。
B、工厂模式(Factory Method)
将对象的创建和使用分开进行,作用是减少类与类之间的耦合度。
工厂模式分三种,简单工厂模式,工厂方法模式,抽象工厂模式。
简单工厂模式
1.定义了一个Product接口,含有方法play
2.提供实现Product接口的实现类
3.定义工厂类(Factory)
4.通过工厂类获取想要的对象,不用再关心具体的细节
工厂方法模式
1.定义抽象产品接口
2.根据抽象产品接口,提供实现产品接口的实现类
3.定义抽象工厂接口
4.为不同的具体产品,给出不同的具体工厂类
5.测试(把自己当作顾客)
抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
C、原型模式(Prototype)
通过将一个对象作为原型,对其进行复制克隆,产生一个与源对象类似的新对象。
原型模式的核心是就是原型类 Prototype,Prototype 类需要具备以下两个条件:
- 实现 Cloneable 接口:
- 重写 Object 类中的 clone() 方法,用于返回对象的拷贝;
Object 类中的 clone() 方法默认是浅拷贝,如果想要深拷贝对象,则需要在 clone() 方法中自定义自己的复制逻辑。
- 浅度克隆:将一个对象复制后,基本数据类型的变量会重新创建,而引用类型指向的还是原对象所指向的内存地址。
- 深度克隆:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。
2、结构模式(7种)
结构模式是优化不同类、对象、接口之间的结构关系。
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
A、适配器模式(Adapter)
搭建两个接口之间的桥梁,使得原本不兼容的两个接口可以兼容。
适配器模式比较适合以下场景:
- (1)系统需要使用现有的类,而这些类的接口不符合系统的接口。
- (2)使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。
B、装饰器模式
对象功能的扩展根据需要来进行动态实现。
装饰器模式的应用场景:
缺点:产生过多相似的对象,不易排错!
- 1 .需要扩展一个类的功能。
- 2. 动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
C、代理模式(Proxy)
为某对象提供一种代理以控制对该对象的访问。
代理模式的实现-多种方法(介绍三种)
1.静态代理
2.动态代理
3.cglib代理第三方提供的代理方式 所以需要导入cglib的依赖
3、行为模式(11种)
行为模式刻画了类和对象交换及分配职责的方式。
策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
A、观察者模式(Observer)
多个对象间存在一对多关系,当一个对象发生改变时,会把这种改变通知给其他多个对象,从而影响其他对象的行为。