创建者模式
这类模式提供创建对象的机制, 能够提升已有代码的灵活性和可复⽤性。 创建者模式包括:⼯⼚⽅法、抽象⼯⼚、⽣成器、原型、单例,这5类。
单例模式
单例模式可以说是整个设计中最简单的模式之⼀,⽽且这种⽅式即使在没有看设计模式相关资料也会常⽤在编码开发中。 因为在编程开发中经常会遇到这样⼀种场景,那就是需要保证⼀个类只有⼀个实例哪怕多线程同时访 问,并需要提供⼀个全局访问此实例的点。 综上以及我们平常的开发中,可以总结⼀条经验,单例模式主要解决的是,⼀个全局使⽤的类频繁的创建和消费,从⽽提升提升整体的代码的性能。
七种单例模式的实现
- 静态类的使用
public class Singleton_00 {
public static Map<String,String> cache = new ConcurrentHashMap<String,String>();
}
以上这种⽅式在我们平常的业务开发中⾮常场常⻅,这样静态类的⽅式可以在第⼀次运⾏的时候直 接初始化Map类,同时这⾥我们也不需要到延迟加载在使⽤。 在不需要维持任何状态下,仅仅⽤于全局访问,这个使⽤使⽤静态类的⽅式更加⽅便。 但如果需要被继承以及需要维持⼀些特定状态的情况下,就适合使⽤单例模式。
spring和IOC容器单例模式就是这种实现方式。
- 懒汉式(线程不安全)
public class Singleton_00 {
private static Singleton_01 instance;
//通过私有化构造器,别人就无法实例化此对象,只能通过提供的API
private Singleton_01(){
}
public static Singleton_01 getInstance(){
if(instance != null) return instance;
instance = new Singleton_01(); //私有方法可以内部调用
return instance;
}
}
⽬前此种⽅式的单例确实满⾜了懒加载,但是如果有多个访问者同时去获取对象实例你可以想象成 ⼀堆⼈在抢厕所,就会造成多个同样的实例并存,从⽽没有达到单例的要求。
如果需要线程安全,就可以通过在方法上添加synchronized关键字来实现线程安全,但是这样的效率还是比较低的。
- 饿汉式(线程安全)
public class Singleton_03 {
private static Singleton_03 instance = new Singleton_03();
private Singleton_03() {
}
public static Singleton_03 getInstance() {
return instance;
}
}
这种方式不是懒加载的,也就是类被加载这个对象就生成了。
- 内部类(线程安全 + 懒加载)
public class Singleton_04 {
//提供静态内部类
private static class SingletonHolder {
private static Singleton_04 instance = new Singleton_04();
}
private Singleton_04() {
}
public static Singleton_04 getInstance() {
return SingletonHolder.instance;
}
}
使⽤类的静态内部类实现的单例模式,既保证了线程安全有保证了懒加载,同时不会因为加锁的⽅式耗费性能。 这主要是因为JVM虚拟机可以保证多线程并发访问的正确性,也就是⼀个类的构造⽅法在多线程环境下可以被正确的加载。此种⽅式也是⾮常推荐使⽤的⼀种单例模式
- 双重锁校验(线程安全)
public class Singleton_05 {
private static Singleton_05 instance;
private Singleton_05() {
}
public static Singleton_05 getInstance(){
if(null != instance) return instance;
synchronized (Singleton_05.class){
if (null == instance){
instance = new Singleton_05();
}
}
return instance;
}
}
双重锁的⽅式是⽅法级锁的优化,减少了部分获取实例的耗时。 同时这种⽅式也满⾜了懒加载。这种方式只有第一次加载可能比较慢。(因为并发可能都去争夺锁资源)
- 枚举方式实现单例
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("doSomething");
}
}
//直接通过Singleton.INSTANCE.doSomething()的方式调用即可。方便、简洁又安全。
public class Main {
public static void main(String[] args) {
Singleton.INSTANCE.doSomething();