一、单例模式
单例模式分为以下8种:
- 饿汉式:
- 静态常量
- 静态代码块
- 懒汉式:
- 线程不安全
- 线程安全,同步方法
- 线程安全,同步代码块
- 双重检查
- 静态内部类
- 枚举
单例模式的使用场景:
需要频繁创建和销毁的对象;创建时耗时过多或消耗资源过多,但又经常用到的对象(比如session工厂、数据源等)
(1)饿汉式 - 静态常量写法
代码实现:
/**
* 设计模式之单例模式
* 饿汉式(静态常量)
*
* @author song
* @create 2020/3/4 15:08
*/
public class SingletonTest01 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次获取的实例一样吗:" + (instance1 == instance2)); //true
}
}
class Singleton {
//私有构造方法,使其不可在外部通过构造器实例化
private Singleton() {
}
//定义为常量,保证实例对象不变
private final static Singleton instance = new Singleton();
//通过此方法获取实例
public static Singleton getInstance() {
return instance;
}
}
分析:
优点:
- 使用方式简单,在类加载的时候创建实例对象,避免了线程同步问题
缺点:
- 在类加载的时候创建实例对象,但不确定何时使用、是否使用,可能造成内存浪费
(2)饿汉式 - 静态代码块写法
代码实现:
/**
* 设计模式之单例模式
* 饿汉式(静态代码块写法)
*
* @author song
* @create 2020/3/4 15:08
*/
public class SingletonTest02 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次获取的实例一样吗:" + (instance1 == instance2)); //true
}
}
class Singleton{
//私有构造方法,使其不可在外部通过构造器实例化
private Singleton(){
}
//定义为常量,保证实例对象不变
private final static Singleton instance;
static {
instance = new Singleton();
}
//通过此方法获取实例
public static Singleton getInstance(){
return instance;
}
}
分析:
和静态常量一致,只不过初始化的位置不同,一个在静态代码块,一个直接在常量声明处初始化
(3)懒汉式 - 线程不安全
代码实现:
/**
* 设计模式之单例模式
* 懒汉式(线程不安全)
*
* @author song
* @create 2020/3/4 15:08
*/
public class SingletonTest03 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次获取的实例一样吗:" + (instance1 == instance2)); //true
}
}
class Singleton {
//私有构造方法,使其不可在外部通过构造器实例化
private Singleton() {
}
//声明实例对象
private static Singleton instance;
//通过此方法获取实例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
分析:
优点:
- 满足随用随拿的特点,解决了内存浪费的问题
缺点:
- 线程不安全,当多个线程访问时,可能创建多个实例,因此实际开发中不可使用
(4)懒汉式 - 线程安全 - 同步方法写法
代码实现:
/**
* 设计模式之单例模式
* 懒汉式(同步方法)
*
* @author song
* @create 2020/3/4 15:08
*/
public class SingletonTest04 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次获取的实例一样吗:" + (instance1 == instance2)); //true
}
}
class Singleton {
//私有构造方法,使其不可在外部通过构造器实例化
private Singleton() {
}
//声明实例对象
private static Singleton instance;
//通过此方法获取实例
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
分析:
虽然解决了线程不安全问题,但锁的范围太大,效率低,开发中尽量不要使用
(5)懒汉式 - 线程安全 - 同步代码块写法
代码实现:
/**
* 设计模式之单例模式
* 懒汉式(同步代码块写法)
*
* @author song
* @create 2020/3/4 15:08
*/
public class SingletonTest05 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次获取的实例一样吗:" + (instance1 == instance2)); //true
}
}
class Singleton {
//私有构造方法,使其不可在外部通过构造器实例化
private Singleton() {
}
//声明实例对象
private static Singleton instance;
//通过此方法获取实例
public static Singleton getInstance() {
if (instance == null) {
//同步代码
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
分析:
这种方式将同步锁缩小了范围,本意是解决效率问题,但又造成了线程不安全,因此开发中不可使用
(6)懒汉式 - 双重检查(推荐使用)
代码实现:
/**
* 设计模式之单例模式
* 双重检查
*
* @author song
* @create 2020/3/4 15:08
*/
public class SingletonTest06 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次获取的实例一样吗:" + (instance1 == instance2)); //true
}
}
class Singleton {
//私有构造方法,使其不可在外部通过构造器实例化
private Singleton() {
}
//声明实例对象
private static volatile Singleton instance;
//双重判断 + 同步锁
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
分析:
既提高了效率也解决了线程安全问题,推荐使用这种方法
(7)懒汉式 - 静态内部类(推荐使用)
代码实现:
/**
* 设计模式之单例模式
* 静态内部类
*
* @author song
* @create 2020/3/4 15:08
*/
public class SingletonTest07 {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println("两次获取的实例一样吗:" + (instance1 == instance2)); //true
}
}
class Singleton {
//私有构造方法,使其不可在外部通过构造器实例化
private Singleton() {
}
//静态内部类
private static class SingletonInstance{
private final static Singleton INSTANCE = new Singleton();
}
//获取实例
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
分析:
利用了类加载机制,保证初始化实例时只有一个线程。Singleton类被装载时并不会被实例化,当调用getInstance方法时才会装载SingletonInstance
(8)懒汉式 - 枚举法(推荐使用)
代码实现:
/**
* 设计模式之单例模式
* 枚举
*
* @author song
* @create 2020/3/4 16:41
*/
public class SingletonTest08 {
public static void main(String[] args) {
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println("两次获取的实例一样吗:" + (instance1 == instance2)); //true
}
}
enum Singleton{
INSTANCE;
}
分析:
不仅能规避线程不安全,还能防止反序列化重新创建新的对象
二、工厂模式
(1)简单工厂模式
- 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
- 定义了一个创建对象的类,由这个类来封装实例化对象的行为
- 在软件开发中,当我们会用到大量的创建某种、某类或某批对象时,就会用到工厂模式
(2)工厂方法模式
定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类进行。
(3)抽象工厂模式
- 定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合
- 抽象工厂模式就是对简单工厂模式的进一步抽象
- 将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
三、原型模式
原型模式是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。
原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
可以通过重写clone方法实现拷贝,拷贝又分为浅拷贝和深拷贝
浅拷贝:
-
对于基本数据类型的成员变量,浅拷贝会直接进行值传递,将该属性值复制一份给新的对象
-
对于引用类型的成员变量,浅拷贝知识将该成员变量的引用值(内存地址)复制一份给新的对象,因此会造成一个对象修改值影响另外一个对象
-
浅拷贝时使用默认的clone()方法来实现,例如:
Person = (Person)super.clone()
深拷贝:
- 复制对象的所有基本数据类型的成员变量值
- 为所有引用类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象
- 可通过重写clone方法和对象序列化方式(推荐)实现
//使用clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Company company = null;
try {
company = (Company) super.clone();
//处理引用类型
company.employee = (Employee) employee.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return company;
}
//使用序列化
protected Object deepClone(){
ByteArrayInputStream bis = null;
ByteArrayOutputStream bos = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
return ois.readObject();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
原型模式的分析:
- 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
- 不用重新初始化对象,而是动态的获取对象运行时的状态
- 如果原始对象发生变化(增加或减少属性),其它克隆对象也会发生变化,无需修改代码
- 浅拷贝和深拷贝对引用类型的处理方式不一样
来源:oschina
链接:https://my.oschina.net/songjilong/blog/3189219