单例模式
一,懒汉模式
懒汉模式是类在加载时不去初始化实例,载入类速度快,但是获取慢,每次获取时需要判断。但是如果一直没有用就一直不会加载。
(1)双重验证模式:
为了保证线程安全,在进入synchronized
代码块之后还要在进行一次验证,以免有两个以上的线程进入synchronized
代码块。用volatile
修饰是避免对象初始化时出现的重排序以及线程的不可见性造成的多次实例。
/**
* @author wghcwc
* 懒汉模式,双重验证,用到时候才加载实例,线程不安全,需要加锁控制
*/
public class Single3 {
/**
*私有化构造函数
*/
private Single3() {
}
/**
* volatile 禁止线程重排序,导致创建多个对象
* 线程可见性导致的创建多个对象
*/
private static volatile Single3 single3;
public static Single3 getInstance() {
if (single3 == null) {
synchronized (Single3.class) {
if (single3 == null) {
//双重验证防止两个以上线程进入synchronized中。
single3 = new Single3();
}
}
}
return single3;
}
}
(2)内部类:
相比于双重验证模式,使用内部类代码更加简洁。巧妙的运用了类初始化时线程安全性。
/**
* @author wghcwc
* 懒汉模式
* 静态内部类,调用getInstance()时候才会加载类,
* 类的静态属性只会在第一次加载类的时候初始化,
* 所以在这里,JVM帮助我们保证了线程的安全性,
* 在类进行初始化时,别的线程是无法进入的。
*/
public class Single4 {
private Single4() {}
private static class Single4Instance {
private static final Single4 INSTANCE = new Single4();
}
public Single4 getInstance() {
return Single4Instance.INSTANCE;
}
}
二,饿汉模式
饿汉模式与懒汉模式主要特征相反,在类加载时就已经初始化好了类的实例,但是不管使不使用,只要类加载了就会初始化类的实例,相对而言不够优雅,但是胜在简洁。
(1)直接初始化:
public class Single1 {
private Single1() {
}
private static Single1 single1 = new Single1();
public static Single1 getInstance() {
return single1;
}
}
(2)静态代码块:
public class Single2 {
private static Single2 instance;
static {
instance = new Single2();
}
private Single2() {
}
public static Single2 getInstance() {
return instance;
}
}
三,枚举
枚举Enum
public enum Single5 {
INSTANCE;
public void prt(){
System.out.println("test");
}
}
INSTANCE为Single5的实例。
第二种:
public enum Singleton {
Instance;
private SingletonEntity se;
public SingletonEntity getInstance() {
se = new SingletonEntity();
return se;
}
}
使用:SingletonEntity se = Singleton.Instance.getInstance();
工厂模式
一,简单工厂模式
定义一个接口,让子类去实现。对象的创建交给工厂去实现。
接口:
public interface Noodle {
/**
* 子类需要实现的功能
* */
void noodle();
}
子类1实现接口:
public class Noodel1 implements Noodle {
@Override
public void noodle() {
System.out.println("noodele1");
}
}
子类2实现接口:
public class Noodel2 implements Noodle {
@Override
public void noodle() {
System.out.println("noodele2");
}
}
工厂创建对象:
public class NodeFactory {
public static Noodle getNoodle(int i) {
switch (i) {
case 1:
return new Noodel1();
case 2:
return new Noodel2();
default:
return new Noodel2();
}
}
}
特点:
扩展性差,每次添加一个新的类需要修改工厂,违反开闭原则。
二,工厂方法模式
工厂方法模式相比与简单工厂模式,代码更加复杂,但是解耦度更高。每个产品对应一个工厂。
工厂接口:
public interface Factory {
Produce create();
}
产品接口:
public interface Produce {
void operate();
}
工厂1:
public class Factory1 implements Factory{
@Override
public Produce create() {
return new Produce1();
}
}
产品1:
public class Produce1 implements Produce {
@Override
public void operate() {
System.out.println("produce1");
}
}
工厂2:
public class Factory2 implements Factory{
@Override
public Produce create() {
return new Produce2();
}
}
产品2:
public class Produce2 implements Produce {
@Override
public void operate() {
System.out.println("produce2");
}
}
使用:
public class Consummer {
public static void main(String[] args) {
Factory factory = new Factory1();
factory.create().operate();
factory = new Factory2();
factory.create().operate();
}
}
缺点:
每次添加新的产品需要添加新的工厂类和消费者类。
三,抽象工厂模式
抽象工厂类似方法工厂,但是抽象工厂不需要知道调用了哪个类即可创建对象。
产品接口1:
public interface IProduce1 {
void use();
}
产品接口2:
public interface IProduce2 {
void use();
}
产品实现1:
public class Produce1 implements IProduce1 {
@Override
public void use() {
System.out.println("produce1");
}
}
产品实现2:
public class Produce2 implements IProduce2 {
@Override
public void use() {
System.out.println("produce2");
}
}
工厂接口:
public interface IFatory {
IProduce1 createProduce1();
IProduce2 createProduce2();
}
工厂实现:
public class Factory implements IFatory {
@Override
public IProduce1 createProduce1() {
return new Produce1();
}
@Override
public IProduce2 createProduce2() {
return new Produce2();
}
}
使用:
public class Consummer {
public static void main(String[] args) {
Factory factory = new Factory();
factory.createProduce1().use();
factory.createProduce2().use();
}
}
缺点:
抽象工厂模式在增加新产品时需要增加新产品类和接口,同时还要修改工厂类的接口以及实现。
结尾
自己常将简单工厂模式以及反射结合使用
NodeFactory
使用反射创建对象:其他的产品实现与简单工厂一样。
public class NodeFactory {
public static <T extends Noodle> Noodle getNoodle(Class<T> clazz) {
try {
return clazz.newInstance();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return null;
}
}
使用:
public class Consummer {
public static void main(String[] args) {
Noodle noodle=NodeFactory.getNoodle(Noodel1.class);
noodle.noodle();
}
}