设计模式之原形模式

定义

指通过拷贝原型来创建新的对象,不需要知道原型对象创建的细节,不调用构造函数

优点

  • 原型模式性能比直接new一个对象性能高
  • 简化创建过程

缺点

  • 原型对象必须有克隆方法
  • 对克隆复杂对象或克隆出的对象进行改造时,容易引入风险

代码实现

如下面的代码,我们通过原型模式来克隆一个User对象。

@Data
public class Address implements Cloneable{

    private String province;

    private String city;

    private String street;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
@Data
public class User implements Cloneable{

    private Long id;

    private String username;

    private String password;

    private Integer age;

    private Character gender;

    private String hobby;

    private Address address;

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

下面我们调用下user的clone方法,看下clone出的对象值。

public class PrototypeMain {

    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setProvince("浙江");
        address.setCity("杭州");
        User user = new User();
        user.setId(1L);
        user.setUsername("admin");
        user.setPassword("123456");
        user.setAddress(address);
        System.out.println("proto: " + user);
        User cloneUser = (User)user.clone();
        System.out.println("clone: " + cloneUser);
        //proto: User(id=1, username=admin, password=123456, age=null, gender=null, hobby=null, address=Address(province=浙江, city=杭州, street=null))
        //clone: User(id=1, username=admin, password=123456, age=null, gender=null, hobby=null, address=Address(province=浙江, city=杭州, street=null))
    }
}

如下面的结果所示,clone出来的结果与原来一致。注意,这里有个坑,我们改下cloneUser的Address的值,再看下原来的user的值

    public class PrototypeMain {

        public static void main(String[] args) throws CloneNotSupportedException {
            Address address = new Address();
            address.setProvince("浙江");
            address.setCity("杭州");
            User user = new User();
            user.setId(1L);
            user.setUsername("admin");
            user.setPassword("123456");
            user.setAddress(address);
            User cloneUser = (User)user.clone();
            cloneUser.getAddress().setProvince("江苏省");
            cloneUser.getAddress().setCity("南京市");
            System.out.println("modify proto: " + user);
            //modify proto: User(id=1, username=admin, password=123456, age=null, gender=null, hobby=null, address=Address(province=江苏省, city=南京市, street=null))
        }
    }

从上面的结果可以看出,原来的user中的address值也被改变掉了。之所以出现这个问题是因为这里的clone实际上是浅copy,对于引用类型,copy的是地址,这里的cloneUser的address和user的address指向的是同一个address。所以改变cloneUser的address,user的address也会被更改。

那么怎么解决这个问题呢?其实很简单,只要将因为类型也重新clone赋值就可以,如下面的代码所示。

@Data
public class User implements Cloneable{

    private Long id;

    private String username;

    private String password;

    private Integer age;

    private Character gender;

    private String hobby;

    private Address address;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        User cloneUser = (User)super.clone();
        Address cloneAddress = (Address)this.address.clone();
        cloneUser.setAddress(cloneAddress);
        return cloneUser;
    }
}

注意,ArrayList等集合框架也是浅Copy,使用时一定要注意这个问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值