设计模式 概述 & 分类(28~28)
1.:设计模式概述:
1)掌握设计模式的层次:(5个阶段)
2)设计模式介绍:(Design Pattern)
2.:设计模式分类:(3种类型)
1)创建型类型(5种):
-1:单例模式:让系统中,某个类的实例只能有一个。
-2:抽象工厂模式:(简单工厂模式 + 工厂方法模式)
-3:原型模式:克隆一个对象,深拷贝 / 浅拷贝。
-4:建造者模式:
-5:工厂模式:
2)结构型类型(7种):
站在软件结构的角度思考的,怎么样软件结构扩展性更好。
-1:适配器模式:
-2:桥接模式:
-3:装饰模式:解决类爆炸问题。
-4:组合模式:
-5:外观模式:
-6:享元模式:
-7:代理模式:
3)行为型类型(11种):
-1:模版方式模式:
-2:命令模式:
-3:访问者模式:
-4:迭代器模式:
-5:观察者模式:
-6:中介者模式:
-7:备忘录模式:
-8:解释器模式(Interpreter 模式):
-9:状态模式:
-10:策略模式:
-11:职责链模式(责任链模式):
一.:创建型—单例模式(29~38)
单例设计模式介绍:(Singleton)(8种)
1)单例设计模式:
-1:所谓的单例设计模式:就是采取一定的方法,保证在整个的软件系统中,对某个类,只能存在一个对象实例。并且该类,只提供一个取得其对象实例的方法。
-2:比如:
a、Hibernate 的 SessionFactory,它充当数据存储源的代理,并负责创建 Session 对象。
b、一般情况下,一个项目通常只需要一个 SessionFactory 就够,这时就会使用到 单例模式。
2)单例设计模式 分类:
-1:饿汉式:类加载时立即创建对象,会导致对象存在时间过长。【 线程安全(static 天然的线程安全的) 】
-2:懒汉式:延迟创建对象,用的时候才创建。【(降低内存消耗,比较好)( 但线程不安全,可手动安全)】
-3:双重检查:可以解决线程安全问题 和 效率问题)
-4:静态内部类:同上
-5:枚举:
1.:饿汉式(1)(静态常量):
1)基本步骤:
-1:构造器私有化:防止外部 new 得到实例。
-2:类的内部创建对象:
-3:向外暴露一个静态的公共方法,获取实例:getInstanse()
2)优缺点说明:
-1:优点:
a、这种写法比较简单,就是在 类装载的时候,就完成实例化,避免了同步问题。
-2:缺点:
a、在类装载的时候,就完成实例化,没有达到 Lazy Loading 的效果。
b、如果从始至终,从未使用过这个实例,则会造成内存的浪费。
-3:说明:
a、这种方式,基于 classloader 机制,避免了多线程同步的问题。
b、不过,instance 在类装载时,就实例化。在单例模式中大多数都是调用 getInstance 方法。
c、但是导致类装载的原因有很多种,因此不能确定有其他的方式(或其他的静态方法)导致类装载。
d、这时候,初始化 instance,就没有达到 Lazy loading 的效果。
-4:结论:
a、这种单例模式可用,可能会造成内存的浪费。
3)代码实现:
/**
* @author zhangxudong@chunyu.me
* @date 2022/3/3 10:48 上午
*/
public class Type1 {
public static void main(String[] args) {
Singleton1 instance1 = Singleton1.getInstance1();
Singleton1 instance2 = Singleton1.getInstance1();
// true
System.out.println(instance1 == instance2);
}
}
class Singleton1 {
//1、构造方法私有化,外部能 new
private Singleton1() {
}
//2、本类内部,创建对象实例
private static final Singleton1 singleton = new Singleton1();
//3、提供一个公有的静态方法,返回实例对象
public static Singleton1 getInstance1() {
return singleton;
}
}
2.:饿汉式(2)(静态代码块):.
1)说明:
-1:这种方式,和【静态常量实现饿汉式】其实类似:
a、只不过将类实例化的过程,放在了静态代码块中。
b、也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。
-2:优缺点和上面一样的:
-3:结论:这种单例模式可用,但是可能造成内存浪费。
2)代码实现:
/**
* @author zhangxudong@chunyu.me
* @date 2022/3/3 11:07 上午
*/
class Singleton2 {
// 1、构造起私有化
private Singleton2() {
}
// 2、
private static final Singleton2 singleton;
// 3、在静态代码块中,创建单例对象
static {
singleton = new Singleton2();
}
public static Singleton2 getInstance() {
return singleton;
}
}
3.:懒汉式(1)(线程不安全):
1)说明:
-1:提供一个静态共有方法,当使用到该方法时,才去创建实例对象。
-2:优点:
a、起到了 Lazy loading 的效果,但是 只能在单线程情况下使用。
-3:缺点:
a、如果在多线程下,多个线程同时进入了 if(singleton == null)判断,这时会创建多个实例。
b、所以:在多线程环境下,不可以使用这种方式。
-4:结论:在实际开发中,不要使用这种方式。
2)代码实现:
/**
* @author zhangxudong@chunyu.me
* @date 2022/3/3 11:21 上午
*/
public class Type3 {
public static void main(String[] args) {
Singleton3 instance1 = Singleton3.getInstance();
Singleton3 instance2 = Singleton3.getInstance();
System.out.println(instance1 == instance2); // true
}
}
class Singleton3 {
private Singleton3() {
}
private static Singleton3 singleton3;
// 提供一个静态共有方法,当使用到该方法时,才去创建实例对象。
public static Singleton3 getInstance() {
if (singleton3 != null) {
singleton3 = new Singleton3();
}
return singleton3;
}
}
4.:懒汉式(2)(线程安全,方法同步):
1)说明:
-1:优点:
a、解决了线程不安全问题。
-2:缺点:
a、效率太低了,每个线程在想获得类的实例的时候,执行 getInstance() 方法,都要进行同步。方法进行同步效率太低。
b、而其实,这个方法只执行一次实例化代码就够了,后面想要获得该类实例,直接 return 就行了。
-3:结论:在实际开发中,不推荐使用这种方式。
2)代码:
/**
* @author zhangxudong@chunyu.me
* @date 2022/3/3 11:34 上午
*/
class Singleton4 {
private Singleton4() {
}
private static Singleton4 singleton4;
// 提供了一个静态共有方法
// 加入了 同步处理 代码,解决了线程安全问题
public static synchronized Singleton4 getInstance() {
if (singleton4 == null) {
singleton4 = new Singleton4();
}
return singleton4;
}
}
5.:懒汉式(3)(线程安全,同步带代码块):
1)说明:
-1:这种方式:本意是对第四种方式的改进,因为前面同步方法效率太低。
-2:但是,这种同步,并不能起到线程同步的作用:
a、跟第三种实现方式,遇到的情形一致,
b、如果在多线程下,多个线程同时进入了 if(singleton == null)判断,这时会创建多个实例。
-3:结论:在实际开发中,不能使用。
2)代码实现:
/**
* @author zhangxudong@chunyu.me
* @date 2022/3/3 11:47 上午
*/
class Singleton5 {
private Singleton5() {
}
private static Singleton5 singleton5;
public static Singleton5 getInstance() {
if (singleton5 == null) {
synchronized (Type5.class) {
singleton5 = new Singleton5();
}
}
return singleton5;
}
}
6.:双重检查:(推荐使用)
1)说明:
-1:Double-check 概念:是多线程开发中常用到的。
a、如代码中所示:我们进行了两次 if(singleton == null )检查,这样可以保证线程安全了。
b、双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。
c、由于 singleton=new Singleton() 对象的创建在 JVM 中可能会进行重排序,在多线程 访问下存在风险,使用 volatile 修饰 singleton 实例变量,可以有效解决该问题。
-2:可以保证 实例化代码只执行一次,避免了多次创建对象。同时避免了反复进行方法同步,效率较高。
-3:优点:
线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线 程情况下能保持高性能。
-4:结论:在实际开发中,推荐使用这种单例设计模式。
2)代码实现:
/**
* @author zhangxudong@chunyu.me
* @date 2022/3/3 11:47 上午
*/
class Singleton5 {
private Singleton5() {
}
// 用 volatile 关键字修饰
// 可以理解为:如果有修改,会立刻更新到储存。(一定程度上可以达到同步效果)
private static