是什么?
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。设计模式存在的根本原因是为了更好地复用代码,增加代码可维护性
六大设计原则:
1.单一职责原则(Single Responsibility Principle ,SRP)
核心思想:应该有且仅有一个原因引起类的变更(一个类只负责一项职责)。
特点:可降低类的复杂度,一个类只负责一项职责;提高类的可读性,提高系统的可维护 性;功能变更引起的风险降低,显著降低对其他功能的影响
2.里氏替换原则(Liskov Substitution Principie , LSP)
核心思想:在使用基类的地方可以任意使用其子类,能保证子类完美替换基类
特点:增强程序的健壮性,增加了子类,原有的子类还可以继续运行(注:如果子类不能完 整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承 关系,采用依赖、聚合、组合等关系代替继承
3.开闭原则(Open Closed Princiiple , OCP)
核心思想:对修改关闭,对扩展开放,可以对已有代码进行扩展,增强程序功能,不能修改 已有代码。
4.依赖倒置原则(Dependence Inversion Principle ,DIP)
核心思想:高层模块不应该依赖底层模块,二者都该依赖其抽象,抽象不应该依赖细节, 细节应该依赖抽象. ——依赖倒置原则的本质就是通过抽象(接口或抽象类)使个各类 或模块的实现彼此独立,互不影响,实现模块间的松耦合; 如果说开闭原则是面向对象设计 的目标的话,那么依赖倒转原则就是面向对象设计的主要手段。
5.接口隔离原则(Interface Segregation Principle , ISP)
核心思想:类间的依赖关系应该建立在最小的接口上,本意就是降低依赖,降低耦合,提升 程序的扩展性和可维护性
说明:如果只设置单一的接口,多个类通过接口相互依赖,必须也要实现很多自身不需要的 方法,就会使程序开发显得很臃肿 ——所以需要对接口进行细化,提高程序设计的灵活 性;使接口用最少的方法完成最多的事情;对依赖接口的类定制服务,专注的为一个模块提 供定制服务,才能建立最小的依赖关系。
6.迪米特法则(Law of Demeter ,LOD)(最少知道原则)
核心思想:一个对象应该对其他对象保持最少的了解,类间解耦
说明:对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外 除了提供的public方法,不对外泄漏任何信息
设计模式分为:创建型模式、结构型模式和行为型模式
创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”
工厂方法模式 (任何可以产生对象的方法或者类都可以称为工厂)
普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建;
创建一个类,同时创建一个工厂类负责生产想要的对象,调用的时候通过调用工厂的方法来创建想要的对象。
定义想要的目标类
调用工厂的创建方法得到目标对象
多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象;
静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
抽象工厂模式
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,一个工厂生产更多的配套产品,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,就用到抽象工厂模式,创建一个抽象的工厂类,抽象工厂类又有多个抽象方法,分别可以用于生产我们所需要的抽象的产品信息比如:抽象的Vehicle/Weapon/Food ,这些抽象类里也有属于自己的抽象方法。方便进行扩展产品一族。(形容词用接口,名词用抽象类来实现)
产品一族,不局限于之前的单一的car ,而是综合性的,比如:工厂不仅生产飞机 ,还生产配套的 武器,飞行员吃的食物等~
然后再建立真实的工厂类来继承抽象工厂,真实的工厂则可以生产出具体我们所需要的类,比如Car/plane 继承自 Vehicle;Bread继承自Food,是对这些抽象类的具现化。根据此种方式,可以更加高效随意的进行生产所需对象 【需要扩展相应的其他产品一族,就会很方便】但其实产品一族产品的扩展会不方便。所以Spring带来了bean工厂
单例模式Singleton:【保证内存中只有单个实例存在,一个类只需要一个实例存在】
饿汉式:线程安全 (常见)
/**
* 饿汉式
* 类加载到内存后,就实例化一个单例,JVM保证线程安全
* 缺点:不管是否用到,类装在时就完成实例化
*/
public class HungryType {
//类加载的时候即创建对象
private static final HungryType INSTANCE = new HungryType();
//不允许其他人new对象,将构造方法私有化
private HungryType() {
}
//对外提供一个方法获得对象
public static HungryType getInstance() {
return INSTANCE;
}
懒汉式:多线程情况下会线程不安全——判断的时候可能多个线程来判断进入,所以要在方法上加锁,解决了安全问题,但是效率变低
/**
* 懒汉式
* 先定义一个对象,在需要的时候再new出来,按需加载
* 多线程情况下会出现线程不安全的问题
*/
public class LazyType {
//首先定义一个静态对象
private static LazyType INSTANCE;
//构造方法私有
private LazyType() {
}
//统一对外提供的获取对象的方法
public static LazyType getInstance() {
if (INSTANCE == null) {
//线程不安全,用睡眠一秒钟,代替有其他业务逻辑
//此时多线程情况下,可能多个线程都判断为null进来,然后各自new对象
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new LazyType();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> System.out.println(LazyType.getInstance().hashCode())).start();
}
}
双重校验锁(因为有指令重排,所以要加volatile)
/**
* 双重校验锁 DCL(DoubleCheckLock)
* 必须加volatile 防止指令重排
* 多线程情况下安全
*/
public class DCLType {
// 增加volatile修饰保证线程之间的可见性
private static volatile DCLType INSTANCE;
private DCLType() {
}
//可以整个方法加锁 但此时锁粒度太粗了,所以可降低锁粒度
public static DCLType getInstance() {
//进行了判断,如果有一个完成了new,就不用参与锁竞争,效率提高
if (INSTANCE == null) {
//如果等于空 进行上锁,上完锁再进行new 完了后释放锁
//双重校验
synchronized (DCLType.class) {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new DCLType();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(DCLType.getInstance().hashCode());
}).start();
}
}
}
静态内部类(比较好的写法——加载的时候,内部类是不会被加载的,调用的时候才会加载)
enum模式(完美,不会被反序列化,枚举类没有构造法反射也没用)
建造者模式(工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。)、
原型模式(原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。本小结会通过对象的复制,进行讲解。在Java中,复制对象是通过clone()实现的)
结构型模式;用于描述如何将类或对象按某种布局组成更多的结构
装饰器模式(Decorator)
在已有的东西上,进行装饰,加上一些装饰品,比如:游戏里面英雄加的皮肤、加了皮肤后攻击特效的改变,都是对目标进行了装饰。——如果用继承方式,不灵活,装饰和被装饰类之间耦合度太高,也不方便各种装饰混合使用 【用聚合代替继承】
桥接模式、适配器模式(适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式)、代理模式、外观模式、组合模式、享元模式
行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。
调停者模式(Mediator)
调停者模式是对象的行为模式。调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显引用。从而使它们可以较松散地耦合。当这些对象中的某些对象之间的相互作用发生改变时,不会立即影响到其他的一些对象之间的相互作用。从而保证这些相互作用可以彼此独立地变化。同时,在需要增加新的一个模块或者对象的时候,可以很方便的加入进来。
观察者模式(Observer)责任链模式(Chain of Responsibility)
策略模式(Strategy)模板方法模式(Template Method)、迭代子模式(Iterator)、命令模式(Command)、备忘录模式(Memento)、状态模式(State)、访问者模式(Visitor)、中介者模式、解释器模式(Interpreter)。
BeanFactory和ApplicationContext应用了工厂模式。
在 Bean 的创建中,Spring 也为不同 scope 定义的对象,提供了单例和原型等模式实现。
AOP 领域则是使用了代理模式、装饰器模式、适配器模式等。各种事件监听器,是观察者模式的典型应用。类似 JdbcTemplate 等则是应用了模板模式。