一、单例模式
1.1 概述
单例模式就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法,即一次创建,终生使用
它有四种实现方式:饿汉式(静态常量/静态代码块)、懒汉式(线程不安全/安全)、静态内部类、枚举
饿汉式意思是提前实现对象的实例化
懒汉式的意思是需要的时候再进行对象的实例化,即Lazy Loading(懒加载)
1.1 饿汉式
1.1.1 静态变量
优点:
- 实现简单
- 在类装载时就完成了实例化,避免了线程同步问题
缺点:
- 在类装载的时候就完成了实例化,没有达到Lazy Loading(懒加载)的效果,容易造成内存的浪费
结论:如果实例经常被调用,则可以使用
1 2 3 4 5 6 7
| public class HungrySingleton{ private static final HungrySingleton instance=new HungrySingleton(); private HungrySingleton(){} public static HungrySingleton getInstance(){ return instance; } }
|
1.1.2 静态代码块
优缺点和静态变量方式一致,就是将对象的初始化放在了静态代码块中
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class HungrySingleton{ private static final HungrySingleton instance; static{ instance=new HungrySingleton(); } private HungrySingleton(){} public static HungrySingleton getInstance(){ return instance; } }
|
1.2 懒汉式
1.2.1 线程不安全
这种方式容易造成线程不安全,在多线程的情况下,如线程a、b、c,a线程通过了判断体后进行了线程的切换,切换到了b线程,那么b线程也能通过判断体,这样就不符合单例模式的要求了,等于对instance进行了两次实例化。所以多线程环境下不能使用这种方式。
结论:不推荐使用
1 2 3 4 5 6 7 8 9
| public class LazySingleton{ private static LazySingleton instance; private LazySingleton(){} public static LazySingleton getInstance(){ if(instance==null) instance=new LazySingleton(); return instance; } }
|
1.2.1 双重校验
解决了线程不同步的问题,在多个线程执行的时候,会有多个线程同时进入第一个判断体中,而第一个判断体有一个同步代码块。同步代码块是需要线程完全执行完里面的操作才进行线程的切换,那么如果前一个线程实现了对象的实例化,那么后面的线程进入同步代码块进行判断的时候,instance就不为空了,保证了线程安全。
声明的变量前的volatile关键字有两个作用:
- 保证变量修改的可见性,如a线程对变量进行修改后,其他线程也能看见修改后的值
- 禁止指令重排
结论:推荐使用
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class LazySingleton{ private static volatile LazySingleton instance=null; private LazySingleton(){} public static LazySingleton getInstance(){ if(instance==null){ synchronized(LazySingleton.class){ if(instance==null) instance=new LazySingleton(); } } return instance; } }
|
1.3 静态内部类
静态内部类方式在类被装载时不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化
类的静态属性只会在第一次加载类的时候初始化,
优点:
- 避免了线程不安全
- 利用静态内部类特点实现延迟加载,效率高
结论:推荐使用
1 2 3 4 5 6 7 8 9 10 11 12
| class Singleton{ private Singleton(){} private static class SingletonInstance{ private static final Singleton INSTANCE = new Singleton();
} public static synchronized Singleton getInstance(){ return SingletonInstance.INSTANCE; } }
|
1.4 枚举
优点:
结论:推荐使用(Effective Java作者推荐)
1 2 3 4 5 6
| enum Singleton{ INSTANCE, public void method(){ } }
|
二、工厂模式
2.1 简单工厂模式
简单工厂设计模式类体如下:
简单来说就是:工厂类Factory可以createProduct()方法传入的标签选择对应的产品类对象的进行创建,这些具体产品类同属于一个抽象的公共产品类
简单工厂的设计在于简单,只有一个工厂类和一个抽象产品类
如果存在多个工厂,多种产品类型,这时就需要用到工厂模式
2.1.1 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class SimpleFactory { public static Product createProduct(String tag){ if ("A".equals(tag)) return new ProductA(); else return new ProductB(); }
public static void main(String[] args) { Product a = SimpleFactory.createProduct("B"); a.use(); } }
abstract class Product{ public void use(){ System.out.print("抽象产品类"); }; }
class ProductA extends Product{ @Override public void use() { super.use(); System.out.println("--->"+"具体产品类A"); } }
class ProductB extends Product{ @Override public void use() { super.use(); System.out.println("--->"+"具体产品类B"); } }
|
2.2 工厂模式
在简单工厂的基础上对工厂类进行抽象,现在可以构建多个具体工厂类了,不同的工厂用于生产不同类的产品
在具体工厂的扩展并不会修改源代码,只需要新建一个工厂类,比如FactoryC用于生产其他产品对象
但如果要新增一个产品类型,并让其中一个工厂进行生产时,这时则需要修改具体工厂类的源代码,不符合开闭原则
2.2.1 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| public abstract class AbstractFactory { abstract Product createProduct(String type);
public Factory(){ Product product = null;
do{ String type = getType(); product = createProduct(type);
if (product == null){ break; } product.use(); }while (true);
}
private String getType() { try { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请在下面输入你要购买产品类型:"); String pizza = reader.readLine(); return pizza; } catch (IOException e) { e.printStackTrace(); return ""; } } }
public abstract class Product { public abstract void use(); }
class FactoryA extends Factory{ @Override Product createProduct(String type) { Product product = null; if("A1".equals(type)) return new ProductA1(); else if("A2".equals(type)) return new ProductA2(); return product; } }
class FactoryB extends Factory{ @Override Product createProduct(String type) { Product product = null; if("B1".equals(type)) return new ProductB1(); else if("B2".equals(type)) return new ProductB2(); return product; } }
class ProductA1 extends Product{ @Override public void use() { System.out.println("使用产品A1"); } }
class ProductA2 extends Product{ @Override public void use() { System.out.println("使用产品A2"); } }
class ProductB1 extends Product{ @Override public void use() { System.out.println("使用产品B1"); } }
class ProductB2 extends Product{ @Override public void use() { System.out.println("使用产品B2"); } }
public class Client { public static void main(String[] args) { Factory factoryA = new FactoryA(); }
}
|
2.3 抽象工厂模式
抽象工厂模式与工厂模式的区别在于将抽象工厂类改成了接口,接口的抽象层次更高,因此称为抽象工厂模式
2.4 应用
三、原型模式
原型模式提供对象复制的一种方式,即对象的克隆,克隆又分为深克隆和浅克隆
浅克隆:复制某一对象时,只复制其本身和值类型的成员变量,不复制引用变量
深克隆:复制某一对象时,不仅复制其本身和值类型的成员变量,还复制引用变量
原型模式结构:
3.1 实现
可以按照原型模式的结构来创建对应的类,但是Java中的Object类提供了一个clone()方法,可以将一个Java对象复制一份。因此在Java中可以直接使用Object提供clone()方法来实现对象的浅克隆
此时Object类相当于抽象原型类,所有实现了Cloneable接口的类相当于具体原型类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class ConcretePrototype implements Cloneable { private String name; private Product product; public Prototype clone() { Object object = null; try { object = super.clone(); } catch (CloneNotSupportedException exception) { System.err.println("Not support Cloneable"); } return (Prototype)object; } }
|
3.2 应用
四、建造者模式
建造者模式结构:
- 抽象建造者:规范产品对象的各个组成部分的建造
- 具体建造者:具体化对象的各个组成部分的创建
- 复杂产品类:需要被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程
- 指挥者类:指挥建造者创建产品的各个部分,并返回产品对象
4.1 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public class Product { private String partA; private String partB; private String partC; }
public abstract class Builder { protected Product product = new Product(); public abstract void buildPartA(); public abstract void buildPartB(); public abstract void buildPartC(); public Product getResult() { return product; } }
public class ConcreteBuilder1 extends Builder { public void buildPartA() { product.setPartA("A1"); } public void buildPartB() { product.setPartA("B1"); } public void buildPartC() { product.setPartA("C1"); } }
public class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } public void setBuilder(Builder builder) { this.builder = builder; } public Product construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); return builder.getResult(); } }
|
4.2 应用