JAVA设计模式(八) -- 原型模式

原型模式属于对象创建模式,GOF 给它的定义为:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

(一)概念梳理

浅复制与深复制概念

1.浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
浅复制

2.深复制(深克隆) 被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
深复制

(二)原型模式的组成结构

1) 客户角色:让一个原型克隆自己来得到一个新对象。
2) 抽象原型角色:实现了自己的 clone 方法,扮演这种角色的类通常是抽象类,且它具有
许多具体的子类。
3) 具体原型角色:被复制的对象,为抽象原型角色的具体子类。

类图:
类图

(三)原型模式的示例代码

(3.1)通过反射实现克隆

抽象原型角色 – Prototype

public abstract class Prototype {
    private int id;
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public abstract Prototype cloneMe() throws Exception;
}

具体原型角色 – ConcretePrototype

public class ConcretePrototype extends Prototype {
    @Override
    public Prototype cloneMe() throws Exception{
        Prototype prototype = new ConcretePrototype ();
        /**1.getFields只能获得类中公共(public)的字段,包含父类中的公共(public)的字段**/
        /**2.getDeclaredFields获得类中所有的字段,包括共有字段和私有字段,默认字段和受保护字段。
                但是不能获得父类中所有的字段**/
        for(Field f: Prototype.class.getDeclaredFields ()){
            String methodName = f.getName ().substring(0,1).toUpperCase()+
                    f.getName ().substring(1); //将属性的首字符大写,方便构造get,set方法
            // 获取属性的类型
            /**若是int类型的id字段,type.getClass()是java.lang.Class的Class对象,
            	而下面语句得到的是int的Class对象**/
            Class type = (Class)f.getGenericType();
            
            //执行get方法
            Object value = prototype.getClass ().getMethod ("get" + methodName).invoke (this, null);
            //执行set方法,参数类型必须传入
            Prototype.class.getDeclaredMethod ("set" +methodName, type)
                    .invoke (prototype, value);
        }
        return prototype;
    }
}

客户端调用 – MAIN

public class Main {
    public static void main(String[] args) throws Exception{
        Prototype prototype = new ConcretePrototype ();
        prototype.setId (1);
        prototype.setName ("简历");
        Prototype copy = prototype.cloneMe ();
        System.out.println (copy.getId () + "-" + copy.getName ());// 1-简历
    }
}

(3.2)通过JAVA原生的clone()实现

Object对象有个clone()方法,实现了对象中各个属性的复制,但它的可见范围是protected的,所以实体类使用克隆的前提是:

① 实现Cloneable接口,这是一个标记接口,自身没有方法。
② 覆盖clone()方法,可见性提升为public。

public class ClonePrototype implements Cloneable{
	private int id;
	private String name;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public Object clone() throws CloneNotSupportedException{
		return super.clone ();
	}
}

测试:

public class Main {

    public static void main(String[] args) throws Exception{
        ClonePrototype clonePrototype = new ClonePrototype ();
        clonePrototype.setId (1);
        clonePrototype.setName ("clone");
        ClonePrototype copyClone = (ClonePrototype) clonePrototype.clone ();
        System.out.println (copyClone.getId () + "-" + copyClone.getName ());//1-clone
    }
}

注:这样只是浅复制,若需要原型和复制品中的引用类型的属性不指向同一内存空间,需要将复制品中的该属性也克隆一遍:

copyProto.referenceObj = proto.referenceObj.clone();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Funnee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值