设计模式(五)——原型模式

问题提出

在软件开发过程中,有时候会遇到为一个类创建多个实例的情况,这些实例内部成员变量完全相同或有细微的差异,而且实例的创建开销远大于或者需要输入较多的参数。如果能通过复制一个已创建的对象实例来重复创建
多个相同的对象,就可以大大减少创建对象的开销,这个时候就需要原型设计模式。

原型模式

原型设计模式是一种创建型模式,按功能分为浅复制和深复制两种情况。

浅复制和深复制

  • 浅复制:如果原型对象的成员变量是值类型,则将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象。
  • 深复制:无论原型对象成员变量是值类型还是引用类型,豆浆复制一份给克隆对象。

实现方法

原型复制常用方法有三种:

  • 利用构造函数方法
  • 利用Cloneable接口方法
  • 利用Serializable接口方法

首先给出要复制的类:

public class Student {
    private String name;
    private int age;
    private Address add;

    public Student(String name, int age, Address add) {
        this.name = name;
        this.age = age;
        this.add = add;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Address getAdd() {
        return add;
    }

    public void setAdd(Address add) {
        this.add = add;
    }
}
public class Address {
    private String pro;
    private String city;
    private String zip;

    public Address(String pro, String city, String zip) {
        this.pro = pro;
        this.city = city;
        this.zip = zip;
    }

    public String getPro() {
        return pro;
    }

    public void setPro(String pro) {
        this.pro = pro;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getZip() {
        return zip;
    }

    public void setZip(String zip) {
        this.zip = zip;
    }
}

利用构造函数方法

浅复制

public class Student {
    // 其他代码相同
    public Student(Student s) {
        name = s.getName();
        age = s.getAge();
        add = s.getAdd();
    }
}
public class Test {
    public static void main(String[] args) {
        Address add = new Address("liaoning","dalian","116081");
        Student s = new Student("zhang",20,add);
        Student s2 = new Student(s);
        System.out.println("s="+s+"\ts2="+s2);
        System.out.println("s.name="+s.getName()+"\ts2.name="+s2.getName());
        System.out.println("s.age="+s.getAge()+"\ts2.age="+s2.getAge());
        System.out.println("s.add="+s.getAdd()+"\ts2.add="+s2.getAdd());
    }
}
OUTPUT
s=Student@41629346	s2=Student@404b9385
s.name=zhang	s2.name=zhang
s.age=20	s2.age=20
s.add=Address@58372a00	s2.add=Address@58372a00

两个add变量的地址相同。

深复制

public class Student {
    // 其他代码相同
    public Student(Student s) {
        name = s.getName();
        age = s.getAge();
        add = new Address(s.getAdd());
    }
}
public class Address {
	// 其他代码相同
    public Address(Address add){
        pro = add.getPro();
        city = add.getCity();
        zip = add.getZip();
    }
}
OUTPUT
s=Student@3b07d329	s2=Student@41629346
s.name=zhang	s2.name=zhang
s.age=20	s2.age=20
s.add=Address@7699a589	s2.add=Address@58372a00

两个add变量的地址不同。显然深复制要比浅复制复杂。

一般例子
举个更一般的例子,用A(B(C(D)))来表示A包含B类引用,B类包含C类引用,C类包含D类引用。若要完成对A类的深复制,必须对引用包含链中的每一个环节都进行处理。

class A {
	// 其他基本成员变量
	private B b;
	A(A a) {
		// 其他基本成员变量的复制
		b = new B(a.getB());
	}
}

class B {
	// 其他基本成员变量
	private C c;
	B(B b) {
		// 其他基本成员变量的复制
		c = new C(b.getC());
	}
}

class C {
	// 其他基本成员变量
	private D d;
	C(C c) {
		// 其他基本成员变量的复制
		d = new D(c.getD());
	}
}

class D {
	// 其他基本成员变量
	D(D d) {
		// 其他基本成员变量的复制
	}
}

利用Cloneable接口方法

Java类都继承自Object类。Object类提供一个clone()方法,可以将Java对象复制一份,因此Java中可以直接使用Clone()方法来实现对象的克隆。但是clone()方法是一个protected保护方法,外部类不能直接调用。

protected native Object clone() throws CloneNotSupportedException;

因此Java语言对对象复制进行了规范:能够实现复制来的Java类必须实现一个标识接口Cloneable。

public interface Cloneable {
}

该接口没有定义任何方法,仅是起到一个标识作用,表达的语义是:该类用到了对象复制功能。
因此抛开本模式而言,空接口有时也很有意义。

浅复制

public class Student implements Cloneable{
    // 其他代码相同
    @Override
    protected Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address add = new Address("liaoning","dalian","116081");
        Student s = new Student("zhang",20,add);
        Student s2 = (Student) s.clone();

        System.out.println("s="+s+"\ts2="+s2);
        System.out.println("s.name="+s.getName()+"\ts2.name="+s2.getName());
        System.out.println("s.age="+s.getAge()+"\ts2.age="+s2.getAge());
        System.out.println("s.add="+s.getAdd()+"\ts2.add="+s2.getAdd());
    }
}
OUTPUT
s=Student@3b07d329	s2=Student@41629346
s.name=zhang	s2.name=zhang
s.age=20	s2.age=20
s.add=Address@7699a589	s2.add=Address@7699a589

深复制

public class Student implements Cloneable {
    // 其他代码相同
    @Override
    protected Object clone() throws CloneNotSupportedException{
        Student s = (Student) super.clone();
        s.setAdd((Address) add.clone());
        return s;
    }
}
public class Address implements Cloneable {
	// 其他代码相同
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Address add = (Address) super.clone();
        return add;
    }
}
OUTPUT
s=Student@41629346	s2=Student@404b9385
s.name=zhang	s2.name=zhang
s.age=20	s2.age=20
s.add=Address@58372a00	s2.add=Address@4dd8dc3

一般例子
A(B(C(D)))

class A implements Cloneable {
	// 其他基本成员变量
	private B b;
	
    @Override
    protected Object clone() throws CloneNotSupportedException{
        A a = (A) super.clone();
        a.setB((B) b.clone());
        return a;
    }
}

class B implements Cloneable {
	// 其他基本成员变量
	private C c;
	
    @Override
    protected Object clone() throws CloneNotSupportedException{
        B b = (B) super.clone();
        b.setC((C) c.clone());
        return b;
    }
}

class C implements Cloneable {
	// 其他基本成员变量
	private D d;
	
    @Override
    protected Object clone() throws CloneNotSupportedException{
        C c = (C) super.clone();
        c.setD((D) d.clone());
        return c;
    }
}

class D implements Cloneable {
	// 其他基本成员变量
    @Override
    protected Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
}

利用Serializable序列化接口方法

深复制
利用构造方法、Cloneable接口方法实现对象深复制都稍显复杂,而利用Serializable序列化接口方法实现深复制则要简单的多。Serializable接口同样是一个空接口。

public class Student implements Cloneable, Serializable {
    // 其他代码相同
    @Override
    protected Object clone() throws CloneNotSupportedException{
        Object obj = null;

        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            // 从流里读回来
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            obj = ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
}
public class Address implements Serializable  {
	// 其他代码相同
}

一般例子
A(B(C(D)))

class A implements Cloneable {
	// 其他代码相同
	private B b;
	
    @Override
    protected Object clone() throws CloneNotSupportedException{
        Object obj = null;

        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);

            // 从流里读回来
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            obj = ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
}

class B implements Serializable {
	// 其他代码相同
}

class C implements Serializable {
	// 其他代码相同
}

class D implements Serializable {
	// 其他代码相同
}

应用示例

原型管理器

原型管理器是对原型的管理类,可以添加原型对象,也可以获得原型对象。

原型管理器,用单例模式实现,用哈希表来维持各原型元素。

public class PrototypeManager {
    private Hashtable ht = new Hashtable();

    private static PrototypeManager pm = new PrototypeManager();

    public static PrototypeManager getPrototypeManager() {
        return pm;
    }

    public void addPrototype(String key, Object obj) {
        ht.put(key, obj);
    }

    public Object getPrototype(String key){
        return ht.get(key);
    }
}

学生类(浅复制)

public class Student implements Cloneable{
    private String name;
    private int age;
    private PubInfo info;

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public PubInfo getInfo() {
        return info;
    }

    public void setInfo(PubInfo info) {
        this.info = info;
    }
}

公共信息类,对于同个大学的所有学生而言是共享的。

public class PubInfo implements Cloneable {
    private String college;
    private String city;
    private String zip;

    public PubInfo(String college, String city, String zip) {
        this.college = college;
        this.city = city;
        this.zip = zip;
    }

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

    public String getCollege() {
        return college;
    }

    public void setCollege(String college) {
        this.college = college;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getZip() {
        return zip;
    }

    public void setZip(String zip) {
        this.zip = zip;
    }
}

现在要求创建m各辽宁师大学生对象、n个大连理工大学学生对象。

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        int m = 10, n = 10;
        PrototypeManager pm = PrototypeManager.getPrototypeManager();

        PubInfo p = new PubInfo("liaoshi", "dalian", "116081");
        Student s = new Student();
        s.setInfo(p);
        pm.addPrototype("liaoshi", s);

        PubInfo p2 = new PubInfo("dagong", "dalian", "116023");
        Student s2 = new Student();
        s2.setInfo(p2);
        pm.addPrototype("dagong", s2);

        Scanner sc = new Scanner(System.in);
        Vector<Student> vec = new Vector<>();
        Student t = (Student) pm.getPrototype("liaoshi");
        for (int i = 0; i < m; i++) {
            Student st = (Student) t.clone();
            st.setName(sc.nextLine());
            st.setAge(sc.nextInt());
            vec.add(st);
        }

        Vector<Student> vec2 = new Vector<>();
        Student t2 = (Student) pm.getPrototype("dagong");
        for (int i = 0; i < m; i++) {
            Student st = (Student) t.clone();
            st.setName(sc.nextLine());
            st.setAge(sc.nextInt());
            vec2.add(st);
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值