设计模式-创建型之原型模式

简介
  • 通过一个实例复制一个一模一样的实例。
使用场景
  • 当我们需要生成一个实例的过程很复杂时,很难根据类来生成实例。我们可以通过复制来生成一个实例。
  • 有时候我们想让生成实例的框架不依赖与具体的类,可以用原型模式。
  • 对象种类繁多,无法将他们整合到一个类的时候。
实现方式1-- 实现Cloneable 接口
  • java为我们提供一个接口Cloneable,只需要我们实现该接口,并重写Object的clone()方法,我们就可以完成克隆。
public class Person implements Cloneable {

    private String name;

    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = null;
        person = (Person) super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
//测试
public class Client {
    public static void main(String[] args) {
        Person tom = new Person("tom", 18);
        try {
            Person clone = tom.clone();
            System.out.println(clone);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
//输出
//Person{name='tom', age=18}
  • 其实这里有一个问题,当属性为引用类型(不包括String)时就会有一个问题,并不会对引用类型的属性进行复制。我们称之为浅拷贝。
public class Person implements Cloneable {

    private String name;
    private int age;
    private Person friend;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person(String name, int age, Person friend) {
        this.name = name;
        this.age = age;
        this.friend = friend;
    }

    public String getName() {
        return name;
    }

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

    public Person getFriend() {
        return friend;
    }

    public void setFriend(Person friend) {
        this.friend = friend;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = null;
        person = (Person) super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", friend=" + friend +
                '}';
    }
}
//测试
public class Client {
    public static void main(String[] args) {
        Person jerry = new Person("Jerry", 16);
        Person tom = new Person("tom", 18,jerry);
        try {
            Person clone = tom.clone();
            //修改 clone 的friend 名字为 jack
            clone.getFriend().setName("Jack");
            System.out.println(clone);
            System.out.println(tom);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
//输出
//Person{name='clone', age=18, friend=Person{name='Jack', age=16, friend=null}}
//Person{name='tom', age=18, friend=Person{name='Jack', age=16, friend=null}}
  • 我们发现 tom的朋友名字也发生了变化,这是不符合实际,也不是我们想要的。
    所以我们需要重写clone()。
public class Person implements Cloneable {

    private String name;
    private int age;
    private Person friend;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name, int age, Person friend) {
        this.name = name;
        this.age = age;
        this.friend = friend;
    }

    public String getName() {
        return name;
    }

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

    public Person getFriend() {
        return friend;
    }

    public void setFriend(Person friend) {
        this.friend = friend;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = null;
        person = (Person) super.clone();
        // 对引用类型进行重新克隆(拷贝)
        if(person.getFriend() != null){
            person.setFriend(person.getFriend().clone());
        }
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", friend=" + friend +
                '}';
    }
}
//测试
public class Client {
    public static void main(String[] args) {
        Person jerry = new Person("Jerry", 16);
        Person tom = new Person("tom", 18,jerry);
        try {
            Person clone = tom.clone();
            //修改 clone 的friend 名字为 jack
            clone.setName("clone");
            clone.getFriend().setName("Jack");
            System.out.println(clone);
            System.out.println(tom);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
//输出
//Person{name='clone', age=18, friend=Person{name='Jack', age=16, friend=null}}
//Person{name='tom', age=18, friend=Person{name='Jerry', age=16, friend=null}}
  • 重写clone()后,就实现类引用类型属性的拷贝。但有一个缺点就是有多个引用类型,我们都需要在clone方法中重新克隆一份。比较麻烦,不利于维护。
实现方式2–实现Serializable
  • 利用序列化来对对象进行深拷贝,使用输入输出流来对对象进行实现。
public class Person implements Serializable {

    private String name;

    private int age;

    private Person friend;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name, int age, Person friend) {
        this.name = name;
        this.age = age;
        this.friend = friend;
    }

    public String getName() {
        return name;
    }

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

    public Person getFriend() {
        return friend;
    }

    public void setFriend(Person friend) {
        this.friend = friend;
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", friend=" + friend +
                '}';
    }
}

//克隆类
public class CloneUtil {

    public static <T extends Serializable>T clone(T obj){
        T clone = null;
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;

        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try{
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);

            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            clone = (T) ois.readObject();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                ois.close();
                bis.close();
                oos.close();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return clone;
    }
}
//测试
public class Client {

    public static void main(String[] args) {
        Person jerry = new Person("Jerry", 16);
        Person tom = new Person("tom", 18,jerry);
        try {
            Person clone = CloneUtil.clone(tom);
            //修改 clone 的friend 名字为 jack
            clone.setName("clone");
            clone.getFriend().setName("Jack");
            System.out.println(clone);
            System.out.println(tom);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值