单例模式

单例模式,顾名思义就是一个类只有一个实例。
单例次要的益处就是,1:能够解决资源拜访抵触的问题。2:缩小资源节约。

单例的实现形式

1:饿汉式

在类加载的时候就实力化对象,不反对提早加载。

public class HungryDemo {    private AtomicInteger id = new AtomicInteger(0);    public static HungryDemo instance = new HungryDemo();    private HungryDemo() {    }    public static HungryDemo getInstance() {        return instance;    }    public int getId() {        return id.incrementAndGet();    }    public static void main(String[] args) {        for (int i = 0; i < 10; i++) {            new Thread(() -> {                try {                    Thread.sleep(new Random().nextInt(10000));                } catch (InterruptedException e) {                    e.printStackTrace();                }                HungryDemo instance = HungryDemo.getInstance();                System.out.println(instance + "==>" + instance.getId());            }).start();        }    }}

2:懒汉式

反对提早加载,在应用的时候才真正加载。

public class LazyDemo {    private AtomicInteger id = new AtomicInteger(0);    public static LazyDemo instance;    private LazyDemo() {    }    public static synchronized LazyDemo getInstance() {        if (Objects.isNull(instance)) {            instance = new LazyDemo();        }        return instance;    }    public int getId() {        return id.incrementAndGet();    }    public static void main(String[] args) {        for (int i = 0; i < 10; i++) {            new Thread(() -> {                try {                    Thread.sleep(new Random().nextInt(10000));                } catch (InterruptedException e) {                    e.printStackTrace();                }                LazyDemo instance = LazyDemo.getInstance();                System.out.println(instance + "==>" + instance.getId());            }).start();        }    }}

饿汉和懒汉的区别就是一个反对提早加载,一个不反对。懒汉模式还要加锁,避免并发问题。从这一点来看,懒汉模式性能是不如饿汉模式,饿汉模式在类加载时就进行实力化,也能够提前将实力化过程中产生的资源有余等问题提前裸露,而不是等到业务拜访后才发现无奈进行初始化,引发线上事变。
但这两种都有各自的有余,所以当初有第三种形式。

3:双重检测

public class DoubleCheckDemo {    private AtomicInteger id = new AtomicInteger(0);    public static DoubleCheckDemo instance;    private DoubleCheckDemo() {    }    public static DoubleCheckDemo getInstance() {        if (Objects.isNull(instance)) {            synchronized (DoubleCheckDemo.class) {                System.out.println("加锁操作");                if (Objects.isNull(instance)) {                    instance = new DoubleCheckDemo();                }            }        }        return instance;    }    public int getId() {        return id.incrementAndGet();    }    public static void main(String[] args) {        for (int i = 0; i < 10; i++) {            new Thread(() -> {                try {                    Thread.sleep(new Random().nextInt(10000));                } catch (InterruptedException e) {                    e.printStackTrace();                }                DoubleCheckDemo instance = DoubleCheckDemo.getInstance();                System.out.println(instance + "==>" + instance.getId());            }).start();        }    }}

双重检测解决了懒汉模式的并发性能问题,同时反对懒加载。

4:动态外部类

动态外部类的实现比双重检测要更加简略,同时也能做到懒加载。

public class InnerClassDemo {    private AtomicInteger id = new AtomicInteger(0);    private InnerClassDemo() {    }    private static class InnerClassDemoHolder {        private static final InnerClassDemo instance = new InnerClassDemo();    }    public static InnerClassDemo getInstance() {        return InnerClassDemoHolder.instance;    }    public int getId() {        return id.incrementAndGet();    }    public static void main(String[] args) {        for (int i = 0; i < 10; i++) {            new Thread(() -> {                try {                    Thread.sleep(new Random().nextInt(10000));                } catch (InterruptedException e) {                    e.printStackTrace();                }                InnerClassDemo instance = InnerClassDemo.getInstance();                System.out.println(instance + "==>" + instance.getId());            }).start();        }    }}

InnerClassDemoHolder 是动态外部类,一开始并不会加载,等到调用getInstance()办法时才会被加载,这是一种无锁的实现,线程平安由jvm来保障。

5:枚举

采纳枚举的形式来实现是最简略的形式。

public enum EnumDemo {    INSTANCE;    private AtomicInteger id = new AtomicInteger(0);    public int getId() {        return id.incrementAndGet();    }}public class EnumDemoTest {    public static void main(String[] args) {        for (int i = 0; i < 10; i++) {            new Thread(() -> {                try {                    Thread.sleep(new Random().nextInt(10000));                } catch (InterruptedException e) {                    e.printStackTrace();                }                EnumDemo instance = EnumDemo.INSTANCE;                System.out.println(instance + "==>" + instance.getId());            }).start();        }    }}

单例模式的问题

  • 单例对OOP个性的反对不敌对,单例对继承,多态个性反对不敌对,违反了面向形象编程的思维。
  • 单例对代码的扩展性不好。
  • 单例对代码的测试性不好,单例往往硬编码进业务,后续mock不不便,须要在一开始就对单例进行包装。
  • 单例不反对有参数的构造函数,单例的设计是无状态的,就无奈进行参数传递来构建实例。

单例的范畴

如果须要在线程内实现单例,能够应用ThreadLocal并发工具类。

如果须要在集群环境下实现单例,能够借助内部共享存储,例如redis。当进行实例创立的时候,从内部存储加载对象,如果没有则创立后存储回去,这里须要分布式锁的接入,实现起来比拟麻烦。

工厂模式

简略工厂

简略工厂能够看作是将对象的创立抽取进去独立的一种实现,这种实现形式比较简单,目标就是将创建对象的负责业务代码从业务中剥离进去,实现复用。
毛病是逻辑过于集中,不利于后续扩大。

工厂办法

工厂办法模式是简略工厂的进一步形象。应用面向对象的多态性,放弃了简略工厂的的长处。将不同的构建逻辑离开到不同的实现中,防止了批改单个逻辑影响所有的构建逻辑。

形象工厂

形象工厂提供一个形象,而不是具体实现。合乎面向形象编程思维,减少工厂也不影响具体业务代码。

建造者模式

比拟典型的实现是lombok的builder办法。

public class BuilderDemo {    private String name;    private int age;    private String phone;    private String email;    private BuilderDemo(BuilderDemoBuilder builder) {        this.name = builder.name;        this.age = builder.age;        this.phone = builder.phone;        this.email = builder.email;    }    public static class BuilderDemoBuilder {        private String name;        private int age;        private String phone;        private String email;        public BuilderDemo build() {            return new BuilderDemo(this);        }        public BuilderDemoBuilder setName(String name) {            if (Objects.isNull(name)) {                throw new IllegalArgumentException("name must not null");            }            this.name = name;            return this;        }        public BuilderDemoBuilder setAge(int age) {            this.age = age;            return this;        }        public BuilderDemoBuilder setPhone(String phone) {            if (Objects.isNull(name)) {                throw new IllegalArgumentException("phone must not null");            }            this.phone = phone;            return this;        }        public BuilderDemoBuilder setEmail(String email) {            this.email = email;            return this;        }    }    public static void main(String[] args) {        BuilderDemo build = new BuilderDemoBuilder().setAge(18).setEmail("email").setName("name").setPhone("13812340987").build();        System.out.println(build.name);    }}

原型模式

基于已有对象原型创建对象。

实现形式分为深拷贝和浅拷贝。深拷贝须要递归负责,创立一个齐全独立的对象。浅拷贝只是拷贝援用地址,适宜不会变的对象。