创建型模式
对类的实例化过程进行抽象,将软件模块中对象的创建和对象的使用分离。
- 单例模式: 全局只有一个对象。
- 工厂模式: 由对象工厂负责生成对象。
- 建造者模式: 组装复杂的实例。
- 原型模式: 通过复制生成实例。
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点。省略创建多个对象所花费的时间和内存空间。
单例模式类的两大特征
构造函数必须为 private ,确保单例不会在系统中的其他代码内被实例化。
实例成员变量和初始化方法必须为 static 。
饿汉方式
在类装载时,立即创建单例对象。
如果一直未被使用,内存空间被浪费;但每次调用时不需要判断,可以节省运行时间。
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getInstance(){
return singleton;
}
// 在后方定义功能
}
枚举类实现。 更简洁,自动支持序列化机制,防止多次实例化。
public enum Singleton {
INSTANCE;
// 在后方定义功能
}
使用时直接使用 Singleton.INSTANCE 对象即可。
懒汉方式
在第一次被使用时,创建单例对象。
synchronized 关键字实现,加同步锁后再新建对象,保证线程安全。
public class Singleton {
private static Singleton singleton;
private Singleton (){
}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
// 在后方定义功能
}
双重锁结构实现,先判断实例对象是否存在,如果不存在不再需要加锁,大大提高了效率。
volatile 关键字用于防止指令重排序。创建对象的过程可能发生重排序,在未给初始化对象赋初值的情况下,就为设置实例对象指向刚分配的内存地址。其他线程在此时可能会通过!=null判断读取到未赋初值的内存空间。
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
// 在后方定义功能
}
static 内部类实现。 和枚举类原理类似,防止多次实例化。
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
// 在后方定义功能
}
工厂模式
在基类中定义创建对象的一个接口,让子类决定实例化哪个类。工厂方法让一个类的实例化延迟到子类中进行。
除了解耦合,把对象的创建和使用的过程分开。工厂模式批量生产对象,还能有效降低代码重复,在业务逻辑发生变化时降低维护成本。 在开源框架中的使用很多,比如 Spring 框架中通过 getBean 方法获取 Bean 。
简单工厂
提供一个统一的工厂类,由用户调用其 static 方法来创建对象。可以根据用户输入参数来返回相应的对象。
public class ShapeFactory {
public static Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
Shape circle = ShapeFactory.getShape("CIRCLE");
如果我们新增产品类的话,就需要修改工厂类中的 getShape 方法。这个弊端可以通过反射机制改善。
public class ShapeFactory {
public static Object getShape(Class<? extends Shape> c) {
Object obj = null;
try {
obj = Class.forName(c.getName()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return obj;
}
}
Circle circle = (Circle) ShapeFactory2.getClass(factory_pattern.Circle.class);
工厂方法
工厂方法模式是简单工厂的仅一步深化。在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说 每个对象都有一个与之对应的工厂 。
// 工厂接口
public interface Factory {
public Shape getShape();
}
// 专用工厂类,还可以有其他工厂类
public class CircleFactory implements Factory {
@Override
public Shape getShape() {
return new Circle();
}
}
抽象工厂
工厂方法模式中专用工厂类只生产单一产品。如果需要生产相互是有关系或有依赖的整套产品,就使用抽象工厂。
public interface Factory {
public Gun produceGun();
public Bullet produceBullet();
}
public class AKFactory implements Factory{
@Override
public Gun produceGun() {
return new AK();
}
@Override
public Bullet produceBullet() {
return new AK_Bullet();
}
}
原型模式
如果要要创建大量相同或相似对象,使用构造函数会比较复杂且耗时耗资源。原型模式用一个已经创建的实例作为原型,通过复制该原型对象来创建新对象。生成对象就很高效。
原型模式的克隆分为浅克隆和深克隆。
浅克隆 复制的变量和原变量的值相同,复制的引用仍指向原有的对象。
深克隆 复制的变量和原变量的值相同,复制的引用将指向被复制的新对象。
浅克隆
由于 Java 提供了对象的 clone 方法,所以用 Java 实现原型模式很简单。
在 java 中自定义类必须实现 Cloneable 接口,并重写 Object 类中的 clone 方法.否则会抛出 CloneNotSupportedException 异常。调用 Object 类的 clone 方法失败时会把异常抛出,应当写在 try-catch 语句中。
// 重写克隆方法
class Realizetype implements Cloneable {
public Object clone() throws CloneNotSupportedException {
return (Realizetype)super.clone();
}
}
public class PrototypeTest {
public static void main(String[] args)throws CloneNotSupportedException {
// 克隆
Realizetype obj1=new Realizetype();
Realizetype obj2=(Realizetype)obj1.clone();
System.out.println("obj1==obj2?"+(obj1==obj2));
}
}
深克隆
通过重写 clone 方法去实现深克隆十分麻烦, 因此引出了另外一种方式:序列化实现深克隆。
在Java语言里深复制一个对象,常常可以先使对象实现 Serializable 接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。
建造者模式
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
- 各个具体的建造者相互独立,有利于系统的扩展。
- 客户端不必知道产品内部组成的细节,便于控制细节风险。
其缺点如下: 产品的组成部分必须相同,这限制了其使用范围。 如果产品的内部变化复杂,该模式会增加很多的建造者类。
建造者(Builder)模式的主要结构,其相关类的代码如下。
产品角色
拆分成多个组成部件的复杂对象。
class Product
{
private String partA;
private String partB;
private String partC;
public void setPartA(String partA)
{
this.partA=partA;
}
public void setPartB(String partB)
{
this.partB=partB;
}
public void setPartC(String partC)
{
this.partC=partC;
}
public void show()
{
System.out.print("show Product");
}
}
建造者
(2) 抽象建造者:包含创建产品各个子部件的抽象方法。 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; } }
(3) 具体建造者:实现了抽象建造者接口。 public class ConcreteBuilder extends Builder { public void buildPartA() { product.setPartA("建造 PartA"); } public void buildPartB() { product.setPartA("建造 PartB"); } public void buildPartC() { product.setPartA("建造 PartC"); } }
指挥者
调用建造者中的方法完成复杂对象的创建。
class Director { private Builder builder; public Director(Builder builder) { this.builder=builder; } //产品构建与组装方法 public Product construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); return builder.getResult(); } }
(5) 客户类
public class Client
{
public static void main(String[] args)
{
// 建造者
Builder builder=new ConcreteBuilder();
// 指挥者控制建造者
Director director=new Director(builder);
// 指挥者建造产品
Product product=director.construct();
// 使用产品
product.show();
}
}