1. 设计模式的分类
1.1 根据目的和用途不同:
- 创建型模式:主要用于创建对象
- 结构型模式:主要用于处理类或对象的组合
- 行为型模式:主要用于描述类或对象的交互以及职责的分配
1.2 根据处理范围不同
- 类模式:处理类和子类之间的关系(这个关系通过继承建立,在编译的时候就已经确定下来了,是静态关系)
- 对象模式:处理对象之间的关系,这些关系在运行的时候时刻变化这,更具有动态性)
2. 详解各个设计模式
2.1 创建型模式
2.1.1 单例模式
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类叫做单列类,它提供全局访问的方法
1. 引入
实现单例模式的核心就是要将构造器私有化;再定义新的支持实例化的方法
1. 代码模拟
public class Singleton {
private static Singleton _instance = null;
private Singleton() { }
public static Singleton Instance()
{
if (_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
public static void main(String[] args) {
Singleton theSingleton = Singleton.Instance();
Singleton anotherSingleton = Singleton.Instance();
System.out.println(theSingleton==anotherSingleton);//true
}
}
2. 实现
单例模式的实现方式有很多:
- 懒汉式单例模型
- 饿汉式单例模型
- 静态内部类实现单例模式
- 枚举实现单例模式
- 双重检测锁实现单例模式
① 懒汉
- 定义
即在想要该对象的时候才去初始化
- 代码
在代码模拟中就是一个懒汉模式
但是上面的懒汉模式存在一个缺点,就是线程不安全,以下提供一个线程安全的代码
public class Singleton {
private static Singleton _instance = null;
private Singleton() { }
public static Singleton Instance()
{
synchronized (Singleton.class){
if (_instance == null)
{
_instance = new Singleton();
}
}
return _instance;
}
}
⚠ ! ! ! ! ! \textcolor{red}{⚠!!!!!} ⚠!!!!! 这样做确实可以保证在多线程情况下的线程安全,但是这样子每次调用 Instance方法去获取 Singleton 对象的时候都会进行加锁操作,会造成比较大的开销,而实际上只有在对 instance 对象进行初始化的时候才需要加锁。
② 饿汉
- 定义
类加载的时候就创建并初始化单例对象
- 代码
public class Singleton {
private static Singleton _instance = new Singleton();
private Singleton() { }
public static Singleton Instance()
{
return _instance;
}
public static void main(String[] args) {
Singleton theSingleton = Singleton.Instance();
Singleton anotherSingleton = Singleton.Instance();
System.out.println(theSingleton==anotherSingleton);//true
}
}
③ 静态内部类
- 定义
使用静态内部类利用了 Java 静态内部类的特性:Java 加载外部类的时候,不会创建内部类的实例,只有在外部类使用到内部类的时候才会创建内部类实例
- 代码
public class Singleton {
private static class SingletonHolder {
private static Singleton singleton= new Singleton();
}
private Singleton() { }
public static Singleton Instance()
{
return SingletonHolder.singleton;
}
public static void main(String[] args) {
Singleton theSingleton = Singleton.Instance();
Singleton anotherSingleton = Singleton.Instance();
System.out.println(theSingleton==anotherSingleton);//true
}
}
④ 枚举
- 定义
枚举是一个特殊的java类,它继承了java.lang.Enum类,所以它不能再继承其它的类,详情请看:https://www.cnblogs.com/bingshen/archive/2022/08/25/16625396.html
- 代码
public class Singleton {
/*构造方法私有化*/
private Singleton(){}
/*静态方法获取实例*/
public static Singleton Instance(){
return InstanceHolder.INSTANCE.getInstance();
}
/*内部类(枚举)实例化外部类*/
private enum InstanceHolder{
INSTANCE();
private Singleton instance;
InstanceHolder(){
instance = new Singleton();
}
public Singleton getInstance(){
return instance;
}
}
public static void main(String[] args) {
Singleton s1 = Singleton.Instance();
Singleton s2 = Singleton.Instance();
System.out.println(s1==s2);
}
}
⑤ 双重检测锁
- 代码
public class Singleton4 {
private volatile static Singleton4 _instance ;
private Singleton4() { }
public static Singleton4 Instance()
{
if(_instance== null){
synchronized (Singleton4.class){
if(_instance == null){
_instance = new Singleton4();
}
}
}
return _instance;
}
public static void main(String[] args) {
Singleton4 theSingleton = Singleton4.Instance();
Singleton4 anotherSingleton = Singleton4.Instance();
System.out.println(theSingleton==anotherSingleton);//true
}
}
2.1.2 原型模式
在系统开发过程中,有时候有些对象需要被频繁的创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后通过复制这个原型对象办法,创建出更多同类型的对象
1. 引入
原型模式的核心就是 克 隆 \textcolor{red}{克隆} 克隆,克隆分为 浅 克 隆 \textcolor{red}{浅克隆} 浅克隆和 深 克 隆 \textcolor{red}{深克隆} 深克隆
浅克隆:仅复制所 考虑的对象,而不复制他所引用的对象(两个人共用同一个脑袋)
深克隆:复制本身之外,对象包含的引用也要复制(两个人各自有各自的脑袋)
1. 代码实现
public class PrototypeSample {
static Prototype Create(char sw) {
if (sw == 'A') {
return new PrototypeA();
} else if (sw == 'B') {
return new PrototypeB();
}
return null;
}
static public void main(String[] args) {
Prototype prototype = Create('A');
prototype.Operation("Hello");
Prototype clone = prototype.Clone();
clone.Operation();
}
}
abstract class Prototype {
abstract public Prototype Clone();
abstract public void Operation(String str);
abstract public void Operation();
}
class PrototypeA extends Prototype {
private String _value = "";
public PrototypeA(){};
public PrototypeA(PrototypeA p) {
_value = p._value;
}
public void Operation(String str) {
_value = str;
System.out.println("update PrototypeA::_value to " + _value);
}
public void Operation() {
System.out.println("PrototypeA::_value is " + _value);
}
public Prototype Clone() {
return new PrototypeA(this);
}
}
class PrototypeB extends Prototype {
private Integer _value = new Integer(-1);
public PrototypeB(){};
public PrototypeB(PrototypeB p) {
_value = p._value;
}
public void Operation(String str) {
_value = Integer.decode(str);
System.out.println("update PrototypeB::_value to " + _value);
}
public void Operation() {
System.out.println("PrototypeB::_value is " + _value);
}
public Prototype Clone() {
return new PrototypeB(this);
}
}