什么是设计模式?
设计模式是解决软件开发某些特定问题而提出的一些解决方案,也可以理解为解决问题的一些固定思路。通过设计模式可以帮助我们增强代码的可复用性、可扩展性、灵活性。我们使用设计模式的最终目的是实现代码的高内聚、低耦合。
面向对象编程中,都有哪些设计原则?
开闭原则
对扩展开放,对修改关闭。就是如果要修改原有的功能或者是扩展功能,尽量去扩展原有的代码,而不是修改原来已有的代码。
里氏替换原则(Liskov Substitution Principle)
任何子类对象都应该可以替换其派生的超类对象 。即,子类可以扩展父类的功能,但不要修改父类原有的功能。 也就是说,当一个子类继承父类后,尽量不要去重写它原有的方法。
依赖转置(依赖倒置)原则
要面向接口编程,不要面向实现编程。两个模块交互时,都访问各自接口,而不是具体的实现类。
单一职责原则
一个对象要专注于一种事情,不要让它担任太多责任。
接口隔离原则
一个接口尽量只包含用户关心的内容。就是一个接口不要太庞大。
迪米特法则
如果两个软件实体之间不是特别必要,尽量不要让他们直接通信。而是找个第三方进行转发,比如使用MQ(消息队列)。
合成复用原则
如果在“组合/聚合”和“继承”之间做抉择时,优先选择“组合/聚合”。
设计模式的分类
设计模式分为:
- 创建型模式:用于创建对象的设计模式。一般可以简化用户创建对象的过程。其次可以降低耦合度,用户不需要关心对象具体的创建过程。
包含:单例模式、原型模型、工厂模式、建造者模式 - 结构型模式:组织对象之间的结构。使其易于扩展等。
包括:代理模式、适配器模式、桥接模式、装饰器模式、外观模式、享元模式、组合模式 - 行为型模式:主要用于决定对象如何做出行为
包括:模板方法模式、策略模式、命令模式、责任链、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式
Spring 框架中⽤到了哪些设计模式?
- ⼯⼚设计模式 : Spring 使⽤⼯⼚模式通过BeanFactory 、ApplicationContext 创建 bean 对象。
- 单例设计模式 : Spring 中的 Bean 默认都是单例的(与传统的单例有所不同)。
- 代理设计模式 : Spring AOP 功能的实现。
- 模板⽅法模式 : Spring 中 jdbcTemplate 、hibernateTemplate 等以Template 结尾的对数据库操作的类,它们就使⽤到了模板模式。
- 装饰器设计模式 : 我们的项⽬需要连接多个数据库,⽽且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的⼀个应⽤。
- 适配器模式 :Spring AOP 的增强或通知(Advice)使⽤到了适配器模式。spring MVC 中也是⽤到了适配器模式适配Controller 。
- 责任链模式:Spring MVC中的HandlerExecutionChain类,就使用到了责任链模式。
- 策略模式:Spring 中的 InstantiationStrategy 接口,根据创建对象情况的不同,提供了Spring Bean实例化的三种策略︰默认构造方法、指定构造方法或者工厂方法。这是一种典型的策略模式。
下面分别进行介绍。
工厂模式
在java中,万物皆对象,如果创建的时候直接new该对象,就会对该对象耦合严重,假如要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则(对扩展开放,对修改关闭。为了使程序的扩展性好,易于维护和升级)。如果使用工厂来生产对象,就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说,工厂模式最大的优点就是:解耦。
工厂模式(Factory Patterm)封装了对象创建的过程,使用者不需要关心对象创建的细节。工厂模式分为三种:简单工厂模式、工厂方法模式和抽象工厂模式。在编码中该模式通常都是以*Factory 的形式呈现。
Spring 中的 BeanFactory就是简单工厂模式的体现,我们可以根据 beanName 在 BeanFactory中获取 bean对象;而Spring 中的FactoryBean就是工厂方法模式的体现,我们可以通过实现FactoryBean 接口并实现其getObject()方法来自定义bean对象。
1. 简单工厂模式
- 什么是简单工厂模式
简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。
- 单工厂的优点/缺点
优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则
2. 工厂方法模式
- 什么是工厂方法模式
工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
- 代码演示:
- 创建产品接口
3. 抽象工厂模式
- 什么是抽象工厂模式
在工厂方法模式中,存在一个缺点,一个工厂只能生产一种产品。如耐克工厂只能生产耐克鞋。但是如果我想让耐克工厂即能生产耐克鞋也可以生产耐克衣服就没办法了。
所以为了解决这个问题,就引出了抽象工厂。在抽象工厂类中定义多个产品,即定义它的子类应该生产哪些产品。 这样就可以做到,耐克厂可以生产耐克鞋和耐克衣服,阿迪工厂可以生产阿迪鞋和阿迪衣服。
简单工厂、工厂方法和抽象工厂三者有什么区别
- 简单工厂:所有的产品都由一个工厂生产。如果你想加产品,就改源代码。
- 工厂方法:有多个工厂,但一个工厂只生产一种产品。如耐克厂只生产耐克鞋,阿迪厂只生产阿迪鞋。如果你想加产品,那就加工厂类。
- 抽象工厂:有多个工厂,每个工厂可以生产多类产品。如耐克厂可以生产耐克鞋和耐克衣服,阿迪厂可以生产阿迪鞋和阿迪衣服。但如果你想生产帽子,那么就需要在抽象工厂里加抽象方法,然后修改所有的子类。
单例模式
单例模式(Singleton Pattern)是最常使用的一种设计模式,它可以确保某一个类只有一个实例,构造⽅法必须是私有的、由⾃⼰创建⼀个静态变量存储实例,对外提供⼀个静态公有⽅法获取实例。在Spring 中,bean 的作用域默认就是单例的。它是通过单例池来确保在Spring容器中只会存在一个对象实例。
Spring的单例与传统单例还是不太一样,它这个单例模式的范围不是传统单例模式中JVM的范围中只有一个实例,而Spring容器在第一次请求该Bean时创建一个实例,并在之后的每次请求中返回同一个实例。这种单例模式与传统的单例模式有些许区别。比如一个UserServive,你还可以再声明几个,只要bean的名称不同就行了。
单例模式的常⻅写法有:
-
饿汉式,线程安全
-
懒汉式,线程不安全
-
懒汉式,线程安全(使用synchronized)
-
双重检查锁(DCL, 即 double-checked locking)
-
静态内部类(推荐)
-
枚举单例
下面对这些常见写法举例:
1. 饿汉式,线程安全
public class Singleton {
// 1、私有化构造⽅法
private Singleton(){
}
// 2、定义⼀个静态变量指向⾃⼰类型
private final static Singleton instance = new Singleton();
// 3、对外提供⼀个公共的⽅法获取实例
public static Singleton getInstance() {
return instance;
}
}
- 优点:实现简单,不需要加锁,线程安全。
- 缺点:在类加载时就创建实例,可能造成资源浪费。
2. 懒汉式,线程不安全
public class Singleton {
// 1、私有化构造⽅法