1、单例模式
1.1 饿汉式
public class TestSingle {
public static void main(String[] args) {
Single instance1 = Single.getSingleHunger();
Single instance2 = Single.getSingleHunger();
System.out.println(instance2 == instance1);
System.out.println(instance2.hashCode());
System.out.println(instance1.hashCode());
}
}
class Single {
private static final Single single = new Single();
private Single() {}
public static Single getSingleHunger() {
return single;
}
}
优缺点:
线程安全
在类加载时就会被创建,没有实现懒加载,可能会浪费资源
1.2 懒汉式
public class TestSingle {
public static void main(String[] args) {
Single instance1 = Single.getSingle();
Single instance2 = Single.getSingle();
System.out.println(instance2 == instance1);
System.out.println(instance2.hashCode());
System.out.println(instance1.hashCode());
}
}
class Single {
private static Single single;
private Single() {}
public static Single getSingle() {
if (single == null) {
single = new Single();
}
return single;
}
}
优缺点:
起到了懒加载效果,但是只能在单线程模式下使用,所有要使用加锁的方式,并使用双重验证提高效率
1.3 双重验证
public class TestSingle {
public static void main(String[] args) {
Single instance1 = Single.getSingle();
Single instance2 = Single.getSingle();
System.out.println(instance2 == instance1);
System.out.println(instance2.hashCode());
System.out.println(instance1.hashCode());
}
}
class Single {
private static Single single;
private Single() {}
public static Single getSingle() {
if (single == null) {
synchronized (Single.class) {
if (single == null) {
single = new Single();
}
}
}
return single;
}
}
优缺点:
- 实例化代码只执行一次后续再次访问,直接return实例对象
- 线程安全,延迟加载,效率较高
1.4 静态内部类
// 测试函数
public class TestSingle {
public static void main(String[] args) {
Single instance1 = Single.getInstance();
Single instance2 = Single.getInstance();
System.out.println(instance2 == instance1);
System.out.println(instance2.hashCode());
System.out.println(instance1.hashCode());
}
}
// 单例模式
class Single {
// 私有化构造函数
private Single(){}
// 静态内部类,当Single类被调用时,静态内部类不会被装载,
// 只有当调用getInstance函数的时候,静态内部类才会被装载,且只会被装载一次(懒加载)
// 而且当类装载的时候是线程安全的,所以该方法是线程安全的,
private static class SingleInstance {
private static Single INSTANCE = new Single();
}
// 提供一个静态的公有方法
public static Single getInstance() {
return SingleInstance.INSTANCE;
}
}
优缺点:
- 采用了类装载机制,保证初始化实例时只有一个线程
- 静态内部类在类装载时并不会立即实例化,而是在需要实例化时,通过调用getInstance方法,才会装载SingleInstance 静态类,从而完成Single 的实例化;
- 类的静态属性只有在第一次加载类的时候初始化,所以是线程安全的
1.5 枚举
public class TestSingle {
public static void main(String[] args) {
Single instance1 = Single.INSTANCE;
Single instance2 = Single.INSTANCE;
System.out.println(instance2 == instance1);
System.out.println(instance2.hashCode());
System.out.println(instance1.hashCode());
}
}
enum Single {
INSTANCE;
public void sayOK() {
System.out.println("ok");
}
}
优缺点:
借助枚举实现单例模式,不仅可以避线程不安全,还能避免通过反序列化重新创建新的对象
单例模式总结
- 单例模式保证了系统中只存在一个对象,节省了系统资源,对于一些需要频繁创建和销毁的对象,使用单例模式可以提高系统性能
- 当实例化一个单例类的时候,要是用相应的获取对象的方法,而不是使用new
- 单例模式使用场景: 需要频繁的进行创建和销毁的对象、创建对象时耗时过多或者耗费资源过多(重量级对象),但是又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)
2、工厂模式
2.1 简单工厂模式
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
步骤1:创建一个接口
public interface Shape {
void draw();
}
步骤2:创建实现接口的实体类
CircleImpl实现类
public class CircleImpl implements Shape {
@Override
public void draw() {
System.out.println("这是一个圆形");
}
}
RectangleImpl 实现类
public class RectangleImpl implements Shape {
@Override
public void draw() {
System.out.println("这是一个矩形");
}
}
SquareImpl 实现类
public class SquareImpl implements Shape {
@Override
public void draw() {
System.out.println("这是一个正方形");
}
}
步骤三:创建一个工厂,生成基于给定信息的实体类对象
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String factoryType) {
if(factoryType == null) {
return null;
}
if (factoryType.equals("圆形")) {
return new CircleImpl();
} else if (factoryType.equals("矩形")) {
return new RectangleImpl();
} else if (factoryType.equals("正方形")) {
return new SquareImpl();
}
return null;
}
}
步骤4:使用该工厂,通过传递类型信息来获取实体类的对象
public class TestFactory {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
Shape shape1 = shapeFactory.getShape("圆形");
shape1.draw();
Shape shape2 = shapeFactory.getShape("矩形");
shape2.draw();
Shape shape3 = shapeFactory.getShape("正方形");
shape3.draw();
Shape shape4 = shapeFactory.getShape("椭圆形");
shape4.draw();
}
}