Skip to content

七大设计原则 ​

强弱关系:依赖<关联<聚合<组合<实现<继承

类与类之间的关系

尚硅谷设计模式笔记

核心思想 &#8203;

  1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

  2. 针对接口编程,而不是针对实现编程

  3. 为了交互对象之间的松耦合设计而努力

合成复用原则 &#8203;

尽量使用合成/聚合来替代继承关系

![image-20231109221935777](Disign Pattern.assets/image-20231109221935777.png)

单一职责原则 &#8203;

接口隔离原则 &#8203;

image-20231106085302425

image-20231106085357180

依赖倒置原则 &#8203;

核心就是面向接口编程; 让细节的具体实现类去依赖(使用)抽象类或者接口;而不是让接口或抽象类去依赖细节的具体实现类.

里氏替换 &#8203;

在面向对象编程语言的继承关系中,父类已经实现的方法,若子类进行修改,可能会产生问题.

使用继承虽然是比较方便的,但是会出现入侵,程序的可移植性降低,程序间的耦合性过高.

根据里氏替换原则,子类中尽量不要重写父类的方法; 所有引用父类的位置,要做到可以透明地使用子类的对象. 如果说子类还是需要父类的方法,可采用聚合,组合,依赖的方式.

开闭原则 &#8203;

最基础最重要的原则

对扩展开放,相对修改关闭

迪米特法则 &#8203;

类和类之间的关系越是复杂,他们的耦合性就会越高.

比如说 类 A依赖类B;那么类A就在内部 把类B的逻辑封装起来;不对外泄露信息.

只要两个对象之间有耦合关系,那么这两个对象就是朋友关系; 出现成员变量,方法参数,方法返回值中的类为直接的朋友; 只与直接的朋友通信.

一般不要将其他类作为局部变量使用.

UML类图 &#8203;

依赖关系 &#8203;

即一个类用到了另一个类, 例如A类中用到了B类;就说A类依赖B类.

可以是类的成员属性,方法的返回类型;方法接收的参数类型;在方法体中用到.

泛化关系 &#8203;

泛化关系就是继承关系; 依赖关系特例

实现关系 &#8203;

实现关系也是依赖关系的特例

关联关系 &#8203;

关联具有导航性质;具有双向或者单向关系; 关联具有多重性; 一对一;多对一, 多对多

聚合关系 &#8203;

聚合表示整体与部分的关系;整体和部分可以分开 是关联关系的特例

组合关系 &#8203;

组合也表示整体与部分的关系;整体和部分不可以分开

人的身份证可以和人分开,但是头部作为人体的组成部分是不能分开的;

java
public class Person{
   private IDCard card;
   private Head head = new Head();
}
//身份证类;
public class IDCard{}
//头部类;
public class Head{}

![image-20231111100319240](Disign Pattern.assets/image-20231111100319240.png)

设计模式分类 &#8203;

设计模式是某类问题的通用解决方案

  • 创建型模式:关注对象的创建。单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
  • 结构型模式:关注软件系统结构,使其更具扩展,更易管理维护。适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
  • 行为型模式:关注方法的思考和设计。模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)

单例模式 &#8203;

一个类把自己的构造方法隐藏起来; 这个类仅存在一个对象实例,且该类对外界只提供一个可以获取对象的方法.

单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(重量级对象),经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等).

单例模式主要有五种: 饿汉式 ;懒汉式; 双重检查 ; 静态内部类 ;枚举

饿汉式 &#8203;

静态常量 &#8203;

java
public class StaticFinal {
    private StaticFinal(){}
    private static final StaticFinal ins = new StaticFinal();

    public static StaticFinal getInstance() {
        return ins;
    }
}

静态代码块 &#8203;

java
class StaticBlock {
    private StaticBlock(){}
    private static StaticBlock ins;
    static{
        ins = new StaticBlock();
    }
    public static StaticBlock getInstance() {
        return ins;
    }
}
  • 使用饿汉式(静态常量版)在类加载的时候就完成实例化。避免了线程同步问题。
  • 需要注意的是类加载的方式有很多种,不能保证用的是getInstance()方法进行的类加载,那么此时的初始化singleton就没有懒加载的效果了;可能会浪费内存.
  • 优点:线程安全
  • 缺点:不是懒加载,可能内存浪费

懒汉式 &#8203;

线程不安全

java
class Singleton1{
    private Singleton1(){}
    private static Singleton1 ins;

    public static Singleton1 getInstance() {
        if(ins==null){
            ins = new Singleton1();
        }
        return ins;
    }
}

优点:实现懒加载

缺点:线程不安全,破坏单例模式

懒汉式(线程安全) &#8203;

java
class Singleton2 {
    private Singleton2() {
    }

    private static Singleton2 ins;

    public static synchronized Singleton2 getInstance() {
        if (ins == null) {
            ins = new Singleton2();
        }
        return ins;
    }
    //或者这种
    //一个线程拿到锁后,其他线程都得排队等待
    public static Singleton2 getInstance() {
        synchronized (Singleton2.class) {
            if (ins == null) {
                ins = new Singleton2();
            }
        }
        return ins;
    }
}

优点:懒加载线程安全

缺点:多线程环境下,每个线程都要排队,效率不高

java
//反射可以破解单例模式    
	public static void main(String[] args) throws Exception {
        Class aClass = Singleton2.class;
        Constructor declaredConstructor = aClass.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Object o = declaredConstructor.newInstance();
        System.out.println(Singleton2.getInstance());
        System.out.println(o);
    }

双重检查懒加载 &#8203;

java
//double check
class Singleton3 {
    private Singleton3() {
    }
    //volatile 线程工作空间中产生变化能马上更新到主内存
    private static volatile Singleton3 ins;
    //即使一个线程先拿到锁,创建完对象,另外的线程可以直接return,不用等待
    public static Singleton3 getInstance() {
        if (ins == null) {
            synchronized (Singleton3.class) {
                if (ins == null) {
                    ins = new Singleton3();
                }
            }
        }
        return ins;
    }
}

减少同步方法执行的次数,兼顾懒加载的需求和多线程的效率,推荐使用

静态内部类懒加载 &#8203;

java
class StaticInner{
    private StaticInner(){}
    //外部类加载的时候,静态内部类不会加载
    private static class StaticIns{
        private static final StaticInner INSTANCE = new StaticInner();
    }
    //只有需要的时候才会创建对象
    public static StaticInner getInstance() {
        return StaticIns.INSTANCE;
    }
}

即实现懒加载,即:我需要的时候再创建对象。又兼顾了线程安全,推荐使用

枚举单例 &#8203;

枚举单例虽然跟饿汉式一样无法实现懒加载,但保证了线程安全,防止反射创建新对象,反序列化重新创建新对象

java
enum EnumSingleton{
    INSTANCE
}