设计模式之原型模式

原型模式

原型模式(Prototype Pattern)是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。即用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。

  • Prototype抽象原型类,声明了clone方法,它可以是接口或基类,可以不用抽象原型类。因为万物皆对象,在Java中Object类是所有类的父类,Object类中有clone方法

  • ConcretePrototype具体原型类,实现或者重写clone方法

原型模式的克隆分为浅克隆和深克隆。

  • 浅克隆 复制的变量和原变量的值相同,复制的引用仍指向原有的对象。

  • 深克隆 复制的变量和原变量的值相同,复制的引用将指向被复制的新对象。

浅克隆

由于 Java 提供了对象的 clone 方法,所以用 Java 实现原型模式很简单。

在 java 中自定义类必须实现 Cloneable 接口,并重写 Object 类中的 clone 方法

public class Student implements Cloneable {

    public String name;

    public int age;

    public Dog dog;

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

    public Student(String name, int age, Dog dog) {
        this.name = name;
        this.age = age;
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", dog=" + dog +
                '}';
    }
}
public class Dog {

    private String name;

    private int age;

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class PrototypeTest {
    public static void main(String[] args)throws CloneNotSupportedException {
        Student stu1 = new Student("张三",18,new Dog("dog",2));
        Student stu2 = (Student)stu1.clone();
        System.out.println(stu1);//Student{name='张三', age=18, dog=Dog{name='dog', age=2}}
        System.out.println(stu2);//Student{name='张三', age=18, dog=Dog{name='dog', age=2}}
        System.out.println(stu1 == stu2); //false
        System.out.println(stu1.dog == stu2.dog); //true
    }
}

通过运行结果发现浅拷贝出来引用类型Dog为同一个对象,若一个对象修改属性势必会影响其它拷贝对象。

如果通过重写 clone() 方法去实现深克隆十分麻烦,需要将Dog类也实现clong()方法并在Student类的clone()中调用 Dog类的clong()因此引出了另外一种方式:序列化实现深克隆。

深克隆

在Java语言里深复制一个对象,常常可以先使对象实现 Serializable 接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。

public class Student implements Serializable {

    public String name;

    public int age;

    public Dog dog;


    protected  Object 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);
            Student student = (Student) ois.readobject();

            return student;
        } catch (Exception e) {
            e.printstacktrace();
            return null;
        } finally {
            //关闭
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                System.out.println(e2.getMessage());
            }

        }
    }

    public Student(String name, int age, Dog dog) {
        this.name = name;
        this.age = age;
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", dog=" + dog +
                '}';
    }
}

public class Dog implements Serializable {

    private String name;

    private int age;

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class PrototypeTest {
    public static void main(String[] args)throws CloneNotSupportedException {
        Student stu1 = new Student("张三",18,new Dog("dog",2));
        Student stu2 = (Student)stu1.deepClone();
        System.out.println(stu1);// Student{name='张三', age=18, dog=Dog{name='dog', age=2}}
        System.out.println(stu2);//Student{name='张三', age=18, dog=Dog{name='dog', age=2}}
        System.out.println(stu1 == stu2); //false
        System.out.println(stu1.dog == stu2.dog); //false
    }
}

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...