4.创建型模式(单例&原型)

1.创建型模式概述

1.1设计模式的分类简述

  • 设计模式有两种分类方式: 1.模式目的 2.模式的作用范围
    • 根据目的来分:即根据模式是用来完成什么工作来划分,可分为如下三种
      1. 创建型模式
      2. 结构型模式
      3. 行为型模式
    • 根据作用范围来分:即根据模式主要用于类上还是用于对象上来分,可分为如下两种
      1. 类模式:处理类和子类之间的关系,通过继承来建立,静态(编译时便确定下来)。
      • 类模式范畴:工厂方法,类适配器,模板方法,解释器
      1. 对象模式:处理对象之间的关系,这些关系可通过组合或聚合来实现,运行时是可变化的,动态
      • 对象模式:除了类模式的四种方法其他都是对象模式

1.2 创建型模式简述

  • 关注点:描述“如何创建对象”
  • 特点:将对象的创建和使用分离(降低系统耦合度)
  • 主要有如下五类创建型模式
    1. 单例模式
    2. 原型模式
    3. 工厂方法
    4. 抽象工厂
    5. 建造者模式

2.单例模式

2.1 单例模式概述

  • 定义:一个类只有一个实例,且该类能自行创建这个实例的一种模式。
  • 特点:单例类只有一个由该单例类自行创建的实例对象,对外提供一个访问该单例的全局访问点。
  • 应用场景
    1. 需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 GC。
    2. 某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。
    3. 某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
    4. 某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
    5. 频繁访问数据库或文件的对象。
    6. 对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。
    7. 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。

优点:
1.单例模式保证内存中只有一个实例,减少内存开销
2.避免对资源多重占用
3.可设置全局访问点,优化和共享资源的访问

缺点:
1.一般没有接口,扩展困难。违背开闭原则
2.并发测试中,单例模式不利于代码调试。且调试过程中若单例中的代码没有执行完,也不能模拟生成一个新得对象。
3.功能代码常写在一个类中,易违背单一职责原则。

2.2 结构与实现

  • 私有化构造函数,静态化实例属性,向外提供一个静态公有函数用于创建/获取静态私有实例。

实现方式1-懒汉式单例

  • 特点:类加载时没有生成单例,第一次调用getInstance方法时创建单例
  • volatile,synchronized保证线程安全,但每次访问时都要同步-影响性能且消耗更多资源

实现示例:

public class SingletonLazy {
	private static volatile SingletonLazy instance = null;
	
	//私有构造方法
	private SingletonLazy(){}

	public static synchronized SingletonLazy getInstance() {
		if (instance == null) {
			instance = new SingletonLazy();
		}
		return instance;
	}
}

实现方式2-饿汉式单例

  • 特点:类加载时就创建一个单例,保证在调用getInstance前单例已存在
  • 类创建时就已创建好一个静态对象供系统使用且以后不再改变-线程安全

实现示例:

class SingletonHungry {
	private static final SingletonHungry instance = new SingletonHungry();

	private SingletonHungry(){}

	public static SingletonHungry getInstance() {
		return instance;
	}
}

扩展-有限多例

  • 将私有静态单例改为私有静态实例列表

实现示例:

class SingletonHungryList {
	private static final ArrayList<SingletonHungryList> list = new ArrayList<>();

	static {
		for (int i = 0; i < 10; i++) {
			list.add(new SingletonHungryList());
		}
	}

	private SingletonHungryList(){}

	public static SingletonHungryList getInstance() {
		int i = (int) Math.random() * 10;
		return list.get(i);
	}
}

2.原型模式

  • 定义: 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象
  • 结构:抽象原型类、具体原型类、访问类
    1. 抽象原型类:规定了具体原型对象必须实现的接口
    2. 具体原型类:实现了抽象原型类的clone()方法,为可被复制的对象
    3. 访问类:使用具体原型类的clone()方法来复制新的对象

优点:
1.Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
2.可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

缺点:
1.需要为每一个类都配置一个 clone 方法
2.clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
3.当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

2.1 原型模式实现

  1. 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,且对于非基本类型属性其仍指向原有属性所指向的对象内存地址
  2. 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆而不再指向原有对象地址。
  • Java中的Object类提供了浅克隆的clone()方法,具体原型类只要实现Cloneable接口就可实现对象的浅克隆(cloneable接口就是抽象原型类)

具体实现(ShallowCopy为具体原型类):

public class Prototype {
	public static void main(String[] args) throws CloneNotSupportedException {
		ShallowCopy s1 = new ShallowCopy();
		ShallowCopy s2 = s1.clone();
		System.out.println("s1与s2内存地址相同吗? " + (s1 == s2));
		System.out.println("s1与s2的o属性地址相同吗? " + (s1.o == s2.o));
	}

}

class ShallowCopy implements Cloneable {
	public InCopy inCopy = new InCopy();

	public ShallowCopy clone() throws CloneNotSupportedException {
		System.out.println("已复制原型对象");
		return (ShallowCopy) super.clone();
	}
}

class InCopy implements Cloneable {

/*    public InCopy clone() throws CloneNotSupportedException {
		System.out.println("已复制原型对象");
		return (InCopy) super.clone();
	}*/
}
/*
已复制原型对象(未注解inCopy内的InCopy时,若注解则s1与s2的inCopy属性地址相同为false)
s1与s2内存地址相同吗? false
s1与s2的inCopy属性地址相同吗? true
 */

扩展-原型管理器原型模式

  • 在原型基础上增加一带原型管理器的PrototypeManager类,用HashMap保存多个复制的原型,Client类可通过管理器的get方法获取复制的原型。
    4.创建型模式(单例&原型)

具体示例:用带原型管理器的原型模式来生成包含“圆”和“正方形”等图形的原型,并计算其面积。分析:本实例中由于存在不同的图形类,例如,“圆”和“正方形”,它们计算面积的方法不一样,所以需要用一个原型管理器来管理它们。
4.创建型模式(单例&原型)

上一篇:git和idea绑定


下一篇:git分支拉取时无法获取到所有的分支内容