设计模式:创建型——建造者模式、原型模式

本文详细介绍了建造者模式和原型模式。建造者模式将对象的构建与表示分离,允许创建不同表示的产品,通过引导者和具体建造者实现。原型模式则通过实现Cloneable接口进行对象拷贝,浅拷贝与深拷贝的区别在于是否拷贝内部对象。文章还探讨了如何实现深拷贝以及这两种设计模式在实际开发中的应用。
摘要由CSDN通过智能技术生成

→23种设计模式大纲

一、建造者模式

定义

将一个对象的构建和表示分离开,使得同样的构建过程可以创建不同的表示

角色

  • 产品 Product :被构造的对象
  • 抽象建造者 Builder :提供被构造对象需要 构造的部分 的方法定义
  • 具体建造者 ConcreteBuilder:实现抽象建造者接口,负责产品的 各个部分的设置,不负责组装
  • 引导者 Director :持有建造者引用,负责指定产品以何种顺序构建

在这里插入图片描述

基础实现

建造者

//抽象建造者
public interface Builder {
    void part1(String part1);
    void part2(String part2);
    void part3(String part3);
    Production build();
}
//具体建造者
class ConcreteBuilder implements Builder{

    Production production=new Production();
    
    @Override
    public void part1(String part1) {
        production.setPart1(part1);
    }

    @Override
    public void part2(String part2) {
        production.setPart2(part2);

    }
    @Override
    public void part3(String part3) {
        production.setPart3(part3);
    }
    @Override
    public Production build(){
        return this.production;
    }
}

引导者、产品

public class Director {

    private Builder builder;

    public Director(Builder builder){
        this.builder=builder;
    }

    public void construct(){
        builder.part1("asd1");
        builder.part2("asd2");
        builder.part3("asd3");
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Production {
    private String part1;
    private String part2;
    private String part3;
}

使用

Builder builder=new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Production production = builder.build();

总结:

  1. 建造者负责每个部分的组装,不参与整体的构造;
  2. 引导者持有建造者的引用;
  3. 建造者内部持有唯一的一个产品;

这种基础的建造者模式在实际使用中,并不多见。另外的变种使用更多。

变种

public class Product {

    private String name;
    private String password;
    private String id;

    public Product(ProductBuilder productBuilder) {
        this.name= productBuilder.name;
        this.password= productBuilder.password;
        this.id= productBuilder.id;
    }

    public static ProductBuilder builder() {
        return new ProductBuilder();
    }

    public static class ProductBuilder {

        private String name;
        private String password;
        private String id;

        public ProductBuilder name(String name) {
            this.name = name;
            return this;
        }

        public ProductBuilder password(String password) {
            this.password = password;
            return this;
        }

        public ProductBuilder id(String id) {
            this.id = id;
            return this;
        }

        public Product build(){
            return new Product(this);
        }
    }
}

像lombok也提供了@Builder注解,将该注解置于实体类上,也可以使用这种变种的建造者模式。
总结一下变种建造者模式的特点:

  • 为实体赋值的操作都发生在Builder内部;
  • 每次赋值完参数后,都返回Builder本身,使得可以不断的链式赋值;
  • 调用builder的build方法时,通过Product的构造方法,完整的构造出Product对象;

二、原型模式

原型模式也叫做克隆模式。
创建一个对象时开销较大,可以拷贝一个已创建的实例,新创建的实例拥有原实例的所有属性。避免出现创建实例时的开销问题。

实现

java实现较为简单:

  • 拷贝的实体实现 Cloneable 接口
  • 拷贝时调用实例的 clone() 方法
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User implements Cloneable{

    private String name;
    private String password;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {
        //使用了Lombok的@Builder注解,所以可以链式赋值
        User user = User.builder().name("asd").password("asdsad").build();
        User clone = (User) user.clone();
	}
}

浅拷贝和深拷贝

前面说过通过拷贝出来的对象和原实例有一样的属性。但是也需要分属性来看的。

浅拷贝:只拷贝原对象。
深拷贝:将原对象内部的其他对象一起拷贝。

例如在User内加入Address的成员变量:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User implements Cloneable{

    private String name;
    private String password;
    private Address address;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class Address implements Cloneable{
    private String id;
    private String area;
    private String city;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

测试内容

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("四川");
        User user = User.builder().name("asd").password("asdsad").address(address).build();
        User clone = (User) user.clone();

        System.out.println("user  " + user);
        System.out.println("clone " + clone);

        address.setArea("北京");

        System.out.println("改变原user中address后 --> user   " + user);
        System.out.println("改变原user中address后 --> clone  " + clone);
    }
}

执行结果

user  User(name=asd, password=asdsad, address=Address(area=四川))
clone User(name=asd, password=asdsad, address=Address(area=四川))
改变原user中address后 --> user   User(name=asd, password=asdsad, address=Address(area=北京))
改变原user中address后 --> clone  User(name=asd, password=asdsad, address=Address(area=北京))

分析一下:新的 user 和原来的 user 持有相同的address引用。所以在修改address内容后,两个user的address对象都发生了改变了。也就是说 内部的 Address 并没有被拷贝

所以此时就需要实现深拷贝了,实现深拷贝一般有两种方法:

  1. 原对象和其内部的所有其他对象都实现 Cloneable接口,再在实体内部统一处理;
  2. 使用序列化来实现深拷贝。需要对象实现Serializable 接口。

这里提一下第一种方式:(还需要Address类实现Cloneable)
这样新拷贝的对象就是深拷贝对象。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User implements Cloneable{

    private String name;
    private String password;
    private Address address;
    @Override
    protected Object clone() throws CloneNotSupportedException {
    //统一做特殊处理
        User clone = (User) super.clone();
        clone.setAddress((Address) this.getAddress().clone());
        return clone;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值