1 设计模式七大原则
1.1 单一职责原则
1.1.1 含义
- 降低类的复杂度,一个类只负责一项职责
- 降低代码更改的影响
- 提供可读性、可维护性
- 通常都需要遵守单一职责原则,逻辑足够简单才可以违反;只有类中方法比较少,可以在方法级别遵守单一职责原则
1.2 开闭原则
- 对提供方开放扩展,对使用方关闭修改
- 尽量通过扩展而不是修改实现功能
- 使用设计模式的目的就是遵守开闭原则
1.3 迪米特原则
- 最小知道法则
- 方法入参、方法返回值和成员变量成为直接朋友,而局部变量称为间接朋友
- 被依赖的类不管逻辑多复杂,都尽量封装到类的内部
- 迪米特法则的核心是:降低类与类之间的耦合,并不是完全没有依赖
1.4 接口隔离原则
- 客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上.
- 示例:如果C依赖1~3方法,而A依赖1、4、5方法,那么依赖关系应该从图1改为图2
1.5 依赖转置原则
1.5.2 特征
- 高层模块不应该依赖底层模块
- 抽象不应该依赖细节
- 中心思想是:面向接口编程
- 理念:抽象的东西相对于细节更稳定
- 接口和抽象类主要是用来搭建规范,细节有具体的实现类来实现
1.5.2 依赖传递的方式
- 接口方式
- 构造器方式
- setter方式
1.5.3 注意事项和细节
- 低层代码尽量要有抽象类和接口
- 变量的声明类型尽量是抽象类或接口
- 继承时遵循里氏替换原则
1.6 里氏替换原则
- 所有的父类都可以透明的使用子类的对象
- 子类尽量不要修改父类的非抽象方法,尽量不要重写父类的方法
- 迫不得已使用聚合、组合和依赖来解决问题,或者抽象个更加基础的类
1.7 合成复用原则
- 尽量使用合成/聚合的方式,而不是使用继承
- 依赖、组合和聚合的区别
- 依赖: 方法入参传入接口等,关联、继承与实现是依赖关系的特例
- 组合:成员变量,通过set方法传入,是关联关系的特例
- 聚合:成员变量,直接new对象,是关联关系的特例
2 UML中类图的简单介绍
2.1 依赖关系
只要用到了,就拥有依赖关系
2.2 泛化关系(继承关系)
泛化关系实际就是继承关系,是依赖关系的特殊情况
比较常见的形式:子类继承了父类,接口继承另一个接口
2.3 实现关系
接口实现等,是依赖关系的特殊情况
比较常见的形式:实现类实现某个接口
2.4 关联关系
类与类的关系,具有导航性和多重性,是依赖关系的特殊情况
2.5 聚合关系
整体与部分的关系,但部分可以与整体分离,是关联关系的特殊情况
比较常见的形式:成员变量中,没有进行初始化,而是使用set方法进行初始化
2.6 组合关系
整体与部分的关系,部分与整体共生死,是关联关系的特殊情况
比较常见的形式:成员变量中,使用new进行了初始化
2.7 UML示意图
3 设计模式分类
模式不是代码,而是通用的解决方案
3.1 创建型设计模式(5种)
- 单例模式
- 工厂模式
- 抽象工厂
- 原型模式
- 建造者模式
3.2 结构型设计模式(7种)
主要是站在类与类关系的角度进行设计
- 适配器模式
- 桥接模式
- 代理模式
- 装饰模式
- 组合模式
- 外观模式
- 享元模式
3.3 行为型设计模式(11种)
主要是站在方法调用的角度上面进行设计
- 策略模式
- 观察者模式
- 中介者模式
- 责任链模式
- 状态模式
- 命令模式
- 模板方法模式
- 备忘录模式
- 解释器模式(拦截器模式)
- 访问者模式
- 迭代器模式
4 创建型设计模式
4.1 单例模式
目的:只允许存在一个实例
实现:
- 饿汉式:静态常量
- 饿汉式:静态代码块
- 懒汉式:线程不安全
- 懒汉式:线程安全,同步方法
- 懒汉式:线程安全,同步代码块
- 双重检查
- 静态内部类
- 枚举类
4.1.1 饿汉式:静态常量
package singleton.type1;
/**
* 饿汉式:静态常量
* 可能会导致内存浪费
*
* @author yi qiang
* @date 2021/5/2 22:07
*/
public class Singleton1 {
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();
Singleton singleton1=Singleton.getInstance();
System.out.println(singleton==singleton1);
System.out.println(singleton.hashCode());
System.out.println(singleton1.hashCode());
}
}
class Singleton{
//1.构造器私有化,使得外部不能通过new创建实例
private Singleton(){
}
//2.本类内部创建一个实例
private static final Singleton INSTANCE=new Singleton();
//3.对外暴露一个公共的静态方法获取实例
public static Singleton getInstance(){
return INSTANCE;
}
}
4.1.2 饿汉式:静态代码块
package singleton.type2;
/**
* 饿汉式:静态代码块
* 可能会导致内存浪费
* @author yi qiang
* @date 2021/5/2 22:07
*/
public class Singleton2 {
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();
Singleton singleton2=Singleton.getInstance();
System.out.println(singleton==singleton2);
}
}
class Singleton{
private static Singleton instance;
//1.构造器私有化,使得外部不能通过new创建实例
private Singleton(){
}
//2.本类内部创建一个实例
static {
instance=new Singleton();
}
//3.对外暴露一个公共的静态方法获取实例
public static Singleton getInstance(){
return instance;
}
}
4.1.3 懒汉式:线程不安全
package singleton.type3;
/**
* 懒汉式:线程不安全 <br>
* 线程不安全,可能会有多个线程进入if(instance==null)中,从而创建多个实例 <br>
* 结论: 不可以使用
* @author yi qiang
* @date 2021/5/2 22:07
*/
public class Singleton3 {
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();
Singleton singleton2=Singleton.getInstance();
System.out.println(singleton==singleton2);
}
}
class Singleton{
private static Singleton instance;
//1.构造器私有化,使得外部不能通过new创建实例
private Singleton(){
}
//2.本类内部创建一个实例
//3.对外暴露一个公共的静态方法获取实例
public static Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
4.1.4 懒汉式:同步方法
package singleton.type4;
/**
* 懒汉式:线程安全 同步方法 <br>
* 线程安全,但是效率太低。多个线程存在时,其他线程都必须等待,而对于getInstance这种需要频繁使用的方法显然不合适 <br>
* 结论: 效率低,不推荐使用
* @author yi qiang
* @date 2021/5/2 22:07
*/
public class Singleton4 {
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();
Singleton singleton2=Singleton.getInstance();
System.out.println(singleton==singleton2);
}
}
class Singleton{
private static Singleton instance;
//1.构造器私有化,使得外部不能通过new创建实例
private Singleton(){
}
//2.本类内部创建一个实例
//3.对外暴露一个公共的静态方法获取实例
public static synchronized Singleton getInstance(){
if(instance==null){
instance= new Singleton();
}
return instance;
}
}
4.1.5 懒汉式:同步代码块
package singleton.type5;
/**
* 懒汉式:线程安全 同步代码块 <br>
* 线程安全,但并非单例。意图解决第四种方案效率低的问题,但实际并不能达到效果 <br>
* 结论: 不可以使用
* @author yi qiang
* @date 2021/5/2 22:07
*/
public class Singleton5 {
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();
Singleton singleton2=Singleton.getInstance();
System.out.println(singleton==singleton2);
}
}
class Singleton{
private static Singleton instance;
//1.构造器私有化,使得外部不能通过new创建实例
private Singleton(){
}
//2.本类内部创建一个实例
//3.对外暴露一个公共的静态方法获取实例
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
instance= new Singleton();
}
}
return instance;
}
}
4.1.6 双重检查
package singleton.type6;
/**
* 双重检验 <br>
* 线程安全,单例,效率比较高 <br>
* 结论: 推荐使用
* @author yi qiang
* @date 2021/5/2 22:07
*/
public class Singleton6 {
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();
Singleton singleton2=Singleton.getInstance();
System.out.println(singleton==singleton2);
}
}
class Singleton{
private static volatile Singleton instance;
//1.构造器私有化,使得外部不能通过new创建实例
private Singleton(){
}
//2.本类内部创建一个实例
//3.对外暴露一个公共的静态方法获取实例
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){
if(instance==null){
instance= new Singleton();
}
}
}
return instance;
}
}
4.1.7 静态内部类
package singleton.type7;
/**
* 静态内部类 <br>
* 利用静态内部类线程安全,且只会初始化一次的特性实现单例<br>
* 结论: 推荐使用
* @author yi qiang
* @date 2021/5/2 22:07
*/
public class Singleton7 {
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();
Singleton singleton2=Singleton.getInstance();
System.out.println(singleton==singleton2);
}
}
class Singleton{
//1.构造器私有化,使得外部不能通过new创建实例
private Singleton(){
}
//2.本类内部创建一个实例
private static class SingletonInner{
private static final Singleton INSTANCE=new Singleton();
}
//3.对外暴露一个公共的静态方法获取实例
public static Singleton getInstance(){
return SingletonInner.INSTANCE;
}
}
4.1.8 枚举单例
package singleton.type8;
/**
* 枚举单例 <br>
* Effective Java推荐的方式<br>
* 结论: 推荐使用
* @author yi qiang
* @date 2021/5/2 22:07
*/
public class Singleton8 {
public static void main(String[] args) {
Singleton singleton=Singleton.INSTANCE;
Singleton singleton2=Singleton.INSTANCE;
System.out.println(singleton==singleton2);
}
}
enum Singleton{
/**
* 单例模式
*/
INSTANCE;
private Singleton(){
}
}