设计模式-创建型模式之原型、建造者设计模式

文章目录

七、原型模式

原型模式 (Prototype Pattern)是用于创建重复的对象,同时又能保证性能。它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口 ,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。

例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

例如:

创建一个可复制的支付类:

java 复制代码
public class WxPay implements Cloneable{
    public WxPay(){
        System.out.println("创建支付对象");
    }
    public WxPay clone() throws CloneNotSupportedException {
        System.out.println("复制对象!");
        return (WxPay) super.clone();
    }
}

使用:

java 复制代码
public class demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        WxPay pay = new WxPay();
        WxPay pay1 = pay.clone();
        System.out.println(pay);
        System.out.println(pay1);
    }
}

可以看到,创建了两个不同的对象,只进行了一次构件函数的执行,当直接创建对象的代价比较大时,就可以采用这种模式。

另外,原型的拷贝又有浅拷贝深拷贝 两个层次,上面的方式就是浅拷贝,只把当前对象做了拷贝,如果对象中有其他对象的引用,就不会进行拷贝,修改任意一个对象中的引用,对其他都会有影响。

比如上面的WxPay类做如下修改:

  1. 先定义其他操作类
java 复制代码
public class OtherOperation {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 再修改WxPay类
java 复制代码
public class WxPay implements Cloneable {

    private OtherOperation otherOperation = new OtherOperation();

    public WxPay() {
        System.out.println("创建支付对象");
    }

    public WxPay clone() throws CloneNotSupportedException {
        System.out.println("复制对象!");
        return (WxPay) super.clone();
    }

    public OtherOperation getOperation() {
        return otherOperation;
    }

    public String getName() {
        return otherOperation.getName();
    }

}
  1. 演示
java 复制代码
public class demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        WxPay pay = new WxPay();
        WxPay pay1 = pay.clone();
        System.out.println(pay);
        System.out.println(pay1);
        System.out.println(pay.getOperation());
        System.out.println(pay1.getOperation());
        pay.getOperation().setName("abc");
        System.out.println(pay1.getOperation().getName());
    }
}

上面可以看出,WxPay确实是复制出了一个实例,但是WxPay里面的OtherOperation实例没有复制,还只向同一个地址,导致只要修改任意一个对象中的OtherOperation对其他实例都会有影响。

上面已经看出默认是浅拷贝,但有的时候,我们又需要其中引用的对象也要为新实例,那怎么做呢,下面就来看下深拷贝的实现方式:

深拷贝实现方式 1:重写 clone 方法来实现深拷贝

深拷贝实现方式 2:通过对象序列化实现深拷贝(推荐)

实现方式 1,重写 clone 方法来实现深拷贝

  1. 修改 OtherOperation类
java 复制代码
public class OtherOperation implements Cloneable{
    private String name;

    public OtherOperation clone() throws CloneNotSupportedException {
        System.out.println("复制OtherOperation对象!");
        return (OtherOperation) super.clone();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 修改WxPay,在clone中再复制OtherOperation ,以达到深拷贝的效果
java 复制代码
public class WxPay implements Cloneable {

    private OtherOperation otherOperation = new OtherOperation();

    public WxPay() {
        System.out.println("创建支付对象");
    }

    public WxPay clone() throws CloneNotSupportedException {
        System.out.println("复制对象!");
        WxPay wxPay = (WxPay) super.clone();
        wxPay.otherOperation = otherOperation.clone();
        return wxPay;
    }

    public OtherOperation getOperation() {
        return otherOperation;
    }

    public String getName() {
        return otherOperation.getName();
    }

}
  1. 演示
java 复制代码
public class demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        WxPay pay = new WxPay();
        WxPay pay1 = pay.clone();
        System.out.println(pay);
        System.out.println(pay1);
        System.out.println(pay.getOperation());
        System.out.println(pay1.getOperation());
        pay.getOperation().setName("abc");
        System.out.println(pay1.getOperation().getName());
    }
}

可以看到,WxPay 和 OtherOperation 都是新实例。

深拷贝实现方式 2:通过对象序列化实现深拷贝

  1. OtherOperation 实现 Serializable
java 复制代码
public class OtherOperation implements  Serializable {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. WxPay 实现Serializable,并提供方法对当前对象进行序列化操作
java 复制代码
public class WxPay implements Serializable {

    private OtherOperation otherOperation = new OtherOperation();

    public WxPay() {
        System.out.println("创建支付对象");
    }

    public OtherOperation getOperation() {
        return otherOperation;
    }

    public String getName() {
        return otherOperation.getName();
    }


    public WxPay deepClone() {
        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); //当前这个对象以对象流的方式输出
            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            return (WxPay) ois.readObject();
        }
        catch (Exception e) {
            return null;
        }
        finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            }
            catch (Exception e2) {
                System.out.println(e2.getMessage());
            }
        }
    }
}
  1. 效果
java 复制代码
public class demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        WxPay pay = new WxPay();
        WxPay pay1 = pay.deepClone();
        System.out.println(pay);
        System.out.println(pay1);
        System.out.println(pay.getOperation());
        System.out.println(pay1.getOperation());
        pay.getOperation().setName("abc");
        System.out.println(pay1.getOperation().getName());
    }
}

和上面我们手动的方式是一样的效果。

八、建造者模式

建造者模式 (Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

例如,在游戏场景中,需要构建人物模型,可能要先构建头部、再构建身体、然后四肢部分,最后才是一个完整的人物,如果都写在一起,肯定会导致代码复杂不易其他开发人员理解,对后期维护扩展难度都大,如果使用构建者模式,便可以将头部、身体、四肢,写在不同的人物实现里面,最后由一个构建类去按照一定的顺序加载它们,然后组成了一个更大的复杂的对象,这样便有利于维护扩展。

下面我们借助上面的例子简单用构建者模式实现下

  1. 定义人物对象,这里直接将头、身体、四肢简化为属性的形式表达。
java 复制代码
@Data
public class Person {
    private String head;
    private String body;
    private String foot;
}
  1. 定义人物构建接口,并定义具体的抽象方法。
java 复制代码
public interface PersonBuilder {
	//构建入口
	Person Builder();
	//构建头部
	void builderHead();
	//构建身体
	void builderBody();
	//构建四肢
	void builderFoot();
}
  1. 定义一个男孩人物的具体构建实现
java 复制代码
public class BoyBuilder implements PersonBuilder {
    private Person person;

    public BoyBuilder() {
        person = new Person();
    }

    @Override
    public Person Builder() {
        builderHead();
        builderBody();
        builderFoot();
        System.out.println("构建完成!");
        return person;
    }

    @Override
    public void builderHead() {
        System.out.println("开始构建男孩头部...");
        person.setHead("男孩头部信息");
    }

    @Override
    public void builderBody() {
        System.out.println("开始构建男孩身体...");
        person.setBody("男孩身体信息");
    }

    @Override
    public void builderFoot() {
        System.out.println("开始构建男孩四肢...");
        person.setFoot("男孩四肢部分信息");
    }
    
}
  1. 演示
java 复制代码
public class demo {

    public static void main(String[] args) {
        PersonBuilder personBuilder = new BoyBuilder();
        Person person = personBuilder.Builder();
        System.out.println(StringFormatter.concat("构建对象:", person.toString()).getValue());
    }
	
}

上面就是将一个人物的不同部分分别构建(实际中每个小的构建都应该在具体的实现中去表达,这里简化为了一个属性),一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

相关推荐
编程、小哥哥31 分钟前
设计模式之抽象工厂模式(替换Redis双集群升级,代理类抽象场景)
redis·设计模式·抽象工厂模式
WaaTong11 小时前
《重学Java设计模式》之 单例模式
java·单例模式·设计模式
WaaTong13 小时前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
霁月风13 小时前
设计模式——观察者模式
c++·观察者模式·设计模式
暗黑起源喵16 小时前
设计模式-工厂设计模式
java·开发语言·设计模式
wrx繁星点点1 天前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
金池尽干1 天前
设计模式之——观察者模式
观察者模式·设计模式
也无晴也无风雨1 天前
代码中的设计模式-策略模式
设计模式·bash·策略模式
捕鲸叉1 天前
MVC(Model-View-Controller)模式概述
开发语言·c++·设计模式
wrx繁星点点1 天前
享元模式:高效管理共享对象的设计模式
java·开发语言·spring·设计模式·maven·intellij-idea·享元模式