创建型设计模式

 创建型设计模式包括:工厂模式、单例模式、建造者(生成器)模式、原型模式。

1、工厂模式(Factory)

  1)简单工厂模式

  工厂模式中会定义一个创建产品对象的工厂接口。如果要创建的产品类型不多(通常为一个或两三个),只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。简单工厂模式中创建实例的方法通常为静态方法,简单来说,简单工厂模式有一个具体的工厂类,可以生成多个不同的产品。简单工厂模式的接口会代替对于产品对象构造函数的直接调用 (即使用 new运算符),不用担心, 对象仍将通过 new运算符创建, 只是该运算符改在工厂方法中调用罢了。只有一种产品类型的简单工厂示例可以参考《JAVA之反射》这篇文章中的动态代理部分。有两种产品的简单工厂示例如下:

class SimpleFactory 
{
    public static Product makeProduct(int kind) 
    {
        switch (kind) 
        {
        case PRODUCT_A:
            return new ProductA();
        case PRODUCT_B:
            return new ProductB();
        default:
            return null;
        }
    }
}
View Code

  2)工厂方法模式

  如果以后要增加产品类型的话,对于简单工厂模式的话就需要修改创建产品实例的方法,使用“工厂方法模式”可以避免修改原来代码。工厂方法模式中的工厂类提供的是创建产品的虚方法或纯虚方法(Java的话即为一个接口),它返回的是产品基类类型。比如一个创建交通工具的工厂,接口返回交通工具类型,想要生产汽车的话就继承工厂类重写创建交通工具的接口,返回汽车类型对象,以后想要生产轮船的话就再增加一个从工程派生的类,然后重写接口:

interface AbstractFactory 
{
    public Product newProduct();
}

class ConcreteAutoFactory implements AbstractFactory {
    public Product newProduct() {

        return new AutoProduct();
    }
}

class ConcreteShipFactory implements AbstractFactory {
    public Product newProduct() {
       
        return new ShipProduct();
    }
}
View Code

  3)抽象工厂模式

  汽车和轮船属于同一基类交通工具,如果有不同类型的产品,比如电脑和手机需要生产的话,可以在“工厂方法模式”的基础上增加一个创建电子类产品的方法,这称为“抽象工厂模式”:

interface AbstractFactory 
{
    public TrafficProduct newTrafficProduct (); //创建交通类工具
    public ElectProduct newElectProduct(); //创建电子类产品
}
View Code

2、单例模式(Singleton)

   单例模式能够保证一个类只有一个实例,这样就可以控制某些共享资源 (例如数据库或文件 的访问权限,避免对共享资源的多重占用,同时只创建一个对象也可以节省内存,避免频繁的创建和销毁对象,加快对象访问速度。例如日志对象一般为单例,数据库连接池也采用单例模式,这样可以节省打开或者关闭数据库连接所引起的效率损耗。

  如下为Java中单例类的实现,可以看到我们并没有将getInstance()方法整体加锁,而是使用了双重检测机制,因为锁机制属于重量级操作,如果每次调用getInstance()都使用锁的话代价就很高,双重检测可以很好的避免这个问题。关于instance为何要使用volatile可以参考《Java线程2》这篇文章里对volatile的讲解。

class Singleton
{
    private static volatile Singleton instance; //实例引用应为static volatile类型
    private Singleton() {} //构造方法设置为私有
    public static Singleton getInstance()
    {
        //双重检测机制避免每次获得实例都加锁
        if(instance == null) 
        {
            synchronized (Singleton.class) {
                if(instance == null)
                {
                    instance = new Singleton();
                }
            }
        }
        
        return instance;
    }
}
View Code

 3、建造者模式(Bulider,又称生成器模式)

  构造方法有时候会有多个参数,但有时这些参数并不是必须的,比如下面的电脑类,cpu和ram是必须的,其它的硬件可以不设置或者部分设置,我们可能想到会使用默认参数或构造函数的重载来优化代码,如下所示,但是这种优化方法对于阅读或者使用者来说并不方便,我们可以使用建造者模式来构建代码。

Computer(String cpu, String ram, int usbCount, String keyboard, String display);
//Computer("双核CPU", "8G内存", 0, "", "");
//Computer("双核CPU", "8G内存", 2, "", "");
//Computer("双核CPU", "8G内存", 2, "机械键盘", "");

//使用默认参数
Computer(String cpu, String ram, int usbCount = 0, String keyboard = "", String display = "");

//使用构造函数的重载
Computer(String cpu, String ram);
Computer(String cpu, String ram, int usbCount);
Computer(String cpu, String ram, int usbCount, String keyboard);
Computer(String cpu, String ram, int usbCount, String keyboard, String display);
View Code

  建造者模式将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。建造者模式的角色主要有产品、建造者、指挥者(又称管理者,可以没有)。当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

  产品:包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。

  建造者:可以分为抽象建造者和具体建造者,抽象建造者包含创建产品各个部件的抽象方法,通常还包含一个返回复杂产品的方法 getResult(),具体建造者实现产品各个部件的具体创建方法。也可以只实现一个具体的建造者。

  指挥者(管理者):将用于创建产品的一系列步骤调用抽取成为单独的方法,你的程序可以不需要指挥者。

class Builder;
class Computer //产品
{
public:
    Computer(std::string  cpu, std::string  ram)  //只有CPU和内存是必须的
    {
        this->cpu = cpu;
        this->ram = ram;
    }
    friend Builder;
private:
    std::string  cpu;//必须
    std::string  ram;//必须
    int              usbCount;//可选
    std::string  keyboard;//可选
    std::string  display;//可选
};

class Builder//建造者
{
public:
    Builder(std::string  cpu, std::string  ram)
    {
        product = new Computer(cpu, ram);
    }

    Computer* getResult() {
        return product;
    }

    virtual void buildUSB(int usbCnt) {
        product->usbCount = usbCnt;
    }
    virtual void buildKeyboard(std::string strKeyboard) {
        product->keyboard = strKeyboard;
    }
    virtual void buildDisplay(std::string strDisplay) {
        product->display = strDisplay;
    }
protected:
    Computer* product;
};

class Director //指挥者(管理者)
{
public:
    Director(Builder* builder) {
        this->builder = builder;
    }

    Computer* construct() {
        builder->buildUSB(2);
        builder->buildDisplay("20寸显示器");
        return builder->getResult();
    }
private:
    Builder* builder;
};

int main()
{
    //不使用指挥者,直接以特定顺序调用创建步骤
    Builder* builder1 = new Builder("双核CPU", "2G内存");
    builder1->buildUSB(2);
    builder1->buildDisplay("20寸显示器");
    Computer* product1 = builder1->getResult();

    //使用指挥者,适合程序中会反复以特定顺序来创建产品
    Builder* builder2 = new Builder("双核CPU", "2G内存");
    Director* director = new Director(builder2);
    Computer* product2 = director->construct();
}
View Code

  生成器模式是 Java 中的一个著名模式 当你需要创建一个可能有许多配置选项的对象时 该模式会特别有用。StringBuilder/StringBuffer的append()、nio.ByteBuffer/CharBuffer/IntBuffer的put()等都使用了该模式。生成器模式可以通过类来识别 它拥有一个构建方法和多个配置结果对象的方法,而且生成器方法通常支持方法链,如someBuilder->setValueA(1)->setValueB(2)->create()。下面是Java使用建造者模式的示例:

class Computer //产品
{
    private final String cpu;//必须
    private final String ram;//必须
    private final int    usbCount;//可选
    private final String keyboard;//可选
    private final String display;//可选

    public static class Builder //建造者
    {
        private String cpu;
        private String ram;
        private int    usbCount;
        private String keyboard;
        private String display;

        public Builder(String cup,String ram){
            this.cpu=cup;
            this.ram=ram;
        }

        public Builder setUsbCount(int usbCount) {
            this.usbCount = usbCount;
            return this;
        }
        public Builder setKeyboard(String keyboard) {
            this.keyboard = keyboard;
            return this;
        }
        public Builder setDisplay(String display) {
            this.display = display;
            return this;
        }

        public Computer build() //生成产品
        {
            return new Computer(this);
        }
    }

    private Computer(Builder builder) //产品类的构造方法设为私有,只允许通过建造者生成产品
    {
        this.cpu=builder.cpu;
        this.ram=builder.ram;
        this.usbCount=builder.usbCount;
        this.keyboard=builder.keyboard;
        this.display=builder.display;
    }
}

public class Main {
    public static void main(String[] args){
        //使用链式调用,一步一步的把产品对象构建出来
        Computer computer=new Computer.Builder("因特尔","三星")
                .setDisplay("三星24寸")
                .setKeyboard("罗技")
                .setUsbCount(2)
                .build();
    }
}
View Code

 4、原型模式(Prototype)

  有的类对象的构建是很复杂或者耗时的,比如对象初始化中需要访问数据库获得数据,如果我们需要多次创建这样的对象的话就很耗时。再比如我们需要构建多个对象,这些对象都需要处于某种原始状态,那么就可以先构建一个拥有这种状态的对象,剩余的对象再通过该对象来复制获得。原型模式就是用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。原型模式包含抽象原型类和具体原型类,抽象原型类规定了具体原型类必须实现的接口,具体原型类里实现抽象原型类的 clone()/copy()方法,它是可被复制的对象。原型对象的克隆方式有深克隆(新对象中的成员变量不再指向原型里成员对象的地址,比如其是new一个新对象然后复制数据)和浅克隆(新对象中的成员变量指向与原型里成员对象的相同):

import java.util.ArrayList;
import java.util.List;

interface Copyable { //抽象原型类
    Copyable copy();
}

class Report implements Copyable { //具体原型类
    private List<String> data;
    public Report() {
        this.data = new ArrayList<>();
    }
    public Report(List<String> data) {
        this.data = data;
    }

    //耗时的数据加载操作
    public void loadData() {
        data.clear();

        //从数据库获得数据
        String str1 = getDataFromMySQL();
        String str2 = getDataFromOracle();

        data.add(str1);
        data.add(str2);
    }

    public List<String> getContents() {
        return data;
    }

    @Override
    public Copyable copy() {
        List<String> cloneList = new ArrayList<>(data); //深拷贝,新对象的数据使用new出来的对象
        //return new Report(data); //浅拷贝,与原型对象共享数据
        return new Report(cloneList);
    }
}

public class Main {
    public static void main(String[] args){
        //创建原型对象
        Report reportPrototype = new Report();
        //耗费资源的操作
        reportPrototype.loadData();

        //使用原型对象构建新的对象
        Report reportWithTitle = (Report) reportPrototype.copy();
    }
}
View Code

  Java中的Cloneable 接口就是抽象原型类(克隆方法为clone()),我们的类只要实现这个接口就实现了原型模式:

class Foo implements Cloneable {
    public Object clone() throws CloneNotSupportedException {
        return super.clone(); // 浅克隆,Object提供了浅克隆的 clone() 方法
    }
}

public class Main {
    public static void main(String[] args)throws CloneNotSupportedException{
        Foo obj1 = new Foo();
        Foo obj2 = (Foo)obj1.clone();
        System.out.println(obj1 == obj2); //false
    }
}
View Code
原文地址:https://www.cnblogs.com/milanleon/p/14954666.html