【设计模式】原型模式与建造者模式

原型模式

原型模式是指通过原型实例指定创建对象的种类,然后通过拷贝的方式创建新的对象。属于创建型模式

原型模式的核心在于拷贝原型对象,主要用于对对象的复制。当你需要通过一大段get/set方法去构建对象的时候,就可以考虑使用原型模式了 我们经常使用的JSON.parseObject() 也是一种原型模式

其类图如下所示
1.原型类IPrototype: 定义一个clone的接口方法,
2.子类: 需要被拷贝的对象
3.Client : 调用clone方法拷贝对象
在这里插入图片描述

实现

public interface IPrototype<T> {
    
    

    T clone();
}

public class PrototypeA implements IPrototype<PrototypeA>{
    
    

    private String name;

    private Integer age;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    @Override
    public PrototypeA clone() {
    
    
        PrototypeA prototypeA = new PrototypeA();
        prototypeA.setAge(this.age);
        prototypeA.setName(this.name);
        return prototypeA;
    }
}

JDK已经提供了一个Cloneable接口,帮我们实现了拷贝的逻辑

public class PrototypeB implements Cloneable{
    
    
    private String name;

    private Integer age;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public PrototypeB clone() {
    
    
        try {
    
    
            return (PrototypeB) super.clone();
        } catch (CloneNotSupportedException e) {
    
    
            throw new RuntimeException(e);
        }
    }
}

深克隆和浅克隆

前面虽然实现了对原型对象的克隆,但它只是复制了值类型数据,对于引用类型对象并没有做一个完整的拷贝,只是简单复制了引用的地址,这会导致克隆后的对象和原型对象之间的数据相互干扰,明显不符合预期(也就是浅克隆)

我们可以用序列化的方式实现深克隆

public class PrototypeB implements Cloneable, Serializable {
    
    
    private String name;

    private Integer age;

    private List<String> friends;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public PrototypeB clone() {
    
    
        try {
    
    
            return (PrototypeB) super.clone();
        } catch (CloneNotSupportedException e) {
    
    
            throw new RuntimeException(e);
        }
    }

    public PrototypeB deepClone() {
    
    
        try {
    
    
            //输出流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);

            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            return (PrototypeB) ois.readObject();
        } catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }
}

可以看出克隆会破坏单例模式,一般情形下我们的单例类都不会实现Cloneable接口,如果需要实现该接口,可以重写clone方法让其在克隆时返回唯一的实例对象

建造者模式

建造者模式: 将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

属于创建型模式

使用场景:

  1. 适合于创建对象需要很多复杂步骤的场景,将复杂对象的创建和使用分离开来
  2. 适合于有多个不同的创建步骤,需要根据不同场景选择不同的顺序

该设计模式中,有以下几个角色:

  1. Product产品:表示要被创建的对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
  2. Builder: 建造者的抽象类,由子类实现其建造过程
  3. ConcreteBuilder:实现Builder的接口以创建满足条件的对象
  4. Director:指导者,由其决定创建复杂对象的步骤

举一个例子: 我手头上有三个任务,我需要根据不同的条件设置需要执行的任务(建造者模式一般采用链式的写法)

public class Product {
    
    

    private String task1;

    private String task2;

    private String task3;

    public String getTask1() {
    
    
        return task1;
    }

    public void setTask1(String task1) {
    
    
        this.task1 = task1;
    }

    public String getTask2() {
    
    
        return task2;
    }

    public void setTask2(String task2) {
    
    
        this.task2 = task2;
    }

    public String getTask3() {
    
    
        return task3;
    }

    public void setTask3(String task3) {
    
    
        this.task3 = task3;
    }

    @Override
    public String toString() {
    
    
        return "Product{" +
                "task1='" + task1 + '\'' +
                ", task2='" + task2 + '\'' +
                ", task3='" + task3 + '\'' +
                '}';
    }
}

public interface IBuilder<T> {
    
    

    T build();

    IBuilder buildTask1(String task);

    IBuilder buildTask2(String task);

    IBuilder buildTask3(String task);


}
public class BuilderA implements IBuilder<Product>{
    
    

    private Product product = null;

    public BuilderA() {
    
    
        this.product = new Product();
    }

    public BuilderA buildTask1(String task) {
    
    
        product.setTask1(task);
        return this;
    }

    public BuilderA buildTask2(String task) {
    
    
        product.setTask2(task);
        return this;
    }
    public BuilderA buildTask3(String task) {
    
    
        product.setTask3(task);
        return this;
    }


    @Override
    public Product build() {
    
    
        return this.product;
    }
}

public class Director {
    
    

    public Product build(IBuilder builder) {
    
    
        builder.buildTask1("任务1");
        builder.buildTask2("任务2");
        return (Product) builder.build();
    }

}
public class Client {
    
    

    public static void main(String[] args) {
    
    
        Director director = new Director();

        Product product = director.build(new BuilderA());
        System.out.println(product);
    }

}

如果被建造的对象只有一个的话,可以省略抽象的Builder和Director,让ConcreteBuilder自己扮演指导者和建造者双重角色,甚至ConcreteBuilder也可以在Product里实现。

建造者模式和工厂模式的区别

  1. 建造者模式更加关注于创建的步骤顺序,而工厂模式更关注于创建的结果-对象
  2. 建造者模式使用不同的步骤创建,最后创建出来的对象不一样,工厂模式创建出来的都是一样的(可以理解为工厂都是批发的)

猜你喜欢

转载自blog.csdn.net/qq_35448165/article/details/129281494