Skip to content

创建型模式

对类的实例化过程进行抽象,将软件模块中对象的创建和对象的使用分离。

  • 单例模式: 全局只有一个对象。
  • 工厂模式: 由对象工厂负责生成对象。
  • 建造者模式: 组装复杂的实例。
  • 原型模式: 通过复制生成实例。

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。省略创建多个对象所花费的时间和内存空间。

单例模式类的两大特征

  1. 构造函数必须为 private ,确保单例不会在系统中的其他代码内被实例化。

  2. 实例成员变量和初始化方法必须为 static 。

饿汉方式

在类装载时,立即创建单例对象。

如果一直未被使用,内存空间被浪费;但每次调用时不需要判断,可以节省运行时间。

java
public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {}
    public static Singleton getInstance(){
        return singleton;
    }
    // 在后方定义功能
}

枚举类实现。 更简洁,自动支持序列化机制,防止多次实例化。

java
public enum Singleton {
    INSTANCE; 
    // 在后方定义功能
}

使用时直接使用 Singleton.INSTANCE 对象即可。

懒汉方式

在第一次被使用时,创建单例对象。

synchronized 关键字实现,加同步锁后再新建对象,保证线程安全。

java
public class Singleton {  
      private static Singleton singleton;  
      private Singleton (){
      }   
      public static synchronized Singleton getInstance() {
	      if (singleton == null) {  
	          singleton = new Singleton();  
	      }  
	      return singleton;  
      } 
      // 在后方定义功能
 }

双重锁结构实现,先判断实例对象是否存在,如果不存在不再需要加锁,大大提高了效率。

volatile 关键字用于防止指令重排序。创建对象的过程可能发生重排序,在未给初始化对象赋初值的情况下,就为设置实例对象指向刚分配的内存地址。其他线程在此时可能会通过!=null判断读取到未赋初值的内存空间。

java
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 内部类实现。 和枚举类原理类似,防止多次实例化。

java
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 方法来创建对象。可以根据用户输入参数来返回相应的对象。

java
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 方法。这个弊端可以通过反射机制改善。

java
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);

工厂方法

工厂方法模式是简单工厂的仅一步深化。在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。也就是说 每个对象都有一个与之对应的工厂 。

java
// 工厂接口
public interface Factory {
    public Shape getShape();
}


// 专用工厂类,还可以有其他工厂类
public class CircleFactory implements Factory {
    @Override
    public Shape getShape() {
        return new Circle();
    }
}

抽象工厂

工厂方法模式中专用工厂类只生产单一产品。如果需要生产相互是有关系或有依赖的整套产品,就使用抽象工厂。

java
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 语句中。

java
// 重写克隆方法
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 接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。


建造者模式

指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

  1. 各个具体的建造者相互独立,有利于系统的扩展。
  2. 客户端不必知道产品内部组成的细节,便于控制细节风险。

其缺点如下: 产品的组成部分必须相同,这限制了其使用范围。 如果产品的内部变化复杂,该模式会增加很多的建造者类。

建造者(Builder)模式的主要结构,其相关类的代码如下。

产品角色

拆分成多个组成部件的复杂对象。

java
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) 客户类

java
public class Client
{
    public static void main(String[] args)
    {
        // 建造者
        Builder builder=new ConcreteBuilder();
        // 指挥者控制建造者
        Director director=new Director(builder);
        // 指挥者建造产品
        Product product=director.construct();
        // 使用产品
        product.show();
    }
}

用心去做高质量的内容网站,欢迎 star ⭐ 让更多人发现