设计模式系列(二)原型模式

设计模式系列(一)单例模式 中详细介绍了单例设计模式,下面一起来看一下原型模式。

一、概述

原型模式是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的。

原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据。

二、深拷贝和浅拷贝

原型模式中的拷贝分为"浅拷贝"和"深拷贝":

浅拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象。

深拷贝: 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制。

三、Java的clone()方法

在Object类中有clone方法

protected native Object clone() throws CloneNotSupportedException;

必须实现Cloneable接口,否则调用clone会返回null

⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:

①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象

②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样

③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

⑵Java中对象的克隆

①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。

②在派生类中覆盖基类的clone()方法,并声明为public。

③在派生类的clone()方法中,调用super.clone()。

④在派生类中实现Cloneable接口。

四、浅复制详解

预先定义好使用的类

package com.designpattern.bean;

/**
 * 机器人实例
 *
 * @author chao
 *
 */
public class Robot {
	public String name;// 名字
	public int age;// 寿命
	public Battery battery;// 电池

	@Override
	public String toString() {
		return "     Robot hashCode:" + hashCode() + " name:" + name + " age:" + age
				+ (battery == null ? "" : battery.toString());
	}

	/**
	 * 电池实例
	 *
	 * @author chao
	 *
	 */
	public static class Battery {
		public String name;// 电池名称
		public int level;// 电池电量 0-100

		@Override
		public String toString() {
			return "      Battery hashCode:" + hashCode() + " name:" + name + " level:" + level;
		}
	}

}

实现浅复制

package com.designpattern.prototype;

import com.designpattern.bean.Robot;

/**
 * 浅克隆
 *
 * @author chao
 *
 */
public class ShallowClone implements Cloneable {
	public Robot robot;
	public String name;
	public int number;

	@Override
	public Object clone() {
		try {
			return super.clone();
		} catch (CloneNotSupportedException e) {
			System.out.println(e.getMessage());
		}
		return null;
	}

	@Override
	public String toString() {
		return "     ShallowClone hashCode:" + hashCode() + " name:" + name + " number:" + number
				+ (robot == null ? "" : robot.toString());
	}
}

测试

package com.designpattern.prototype;

import com.designpattern.bean.Robot;
import com.designpattern.bean.Robot.Battery;

public class CloneTest {

	public static void main(String[] args) {
		testShallowClone();

	}

	private static void testShallowClone() {
		ShallowClone shallowClone = new ShallowClone();
		shallowClone.name = "1";
		shallowClone.number = 1;
		shallowClone.robot = new Robot();
		shallowClone.robot.name = "1";
		shallowClone.robot.battery = new Battery();
		shallowClone.robot.battery.name = "1";
		System.out.println(shallowClone.toString());
		ShallowClone shallowClone2 = (ShallowClone) shallowClone.clone();
		System.out.println(shallowClone2.toString());
		shallowClone.name = "2";
		shallowClone.number = 2;
		shallowClone.robot.name = "2";
		shallowClone.robot.battery.name = "2";
		System.out.println(shallowClone.toString());
		System.out.println(shallowClone2.toString());

	}
}

结果

     ShallowClone hashCode:1704856573 name:1 number:1     Robot hashCode:705927765 name:1 age:0      Battery hashCode:366712642 name:1 level:0
     ShallowClone hashCode:1829164700 name:1 number:1     Robot hashCode:705927765 name:1 age:0      Battery hashCode:366712642 name:1 level:0
     ShallowClone hashCode:1704856573 name:2 number:2     Robot hashCode:705927765 name:2 age:0      Battery hashCode:366712642 name:2 level:0
     ShallowClone hashCode:1829164700 name:1 number:1     Robot hashCode:705927765 name:2 age:0      Battery hashCode:366712642 name:2 level:0

结果分析:

我们对ShallowClone 的对象shallowClone浅复制出对象shallowClone1,这两个对象输出,属性值完全相同,但是这两个对象分配了不同的内存空间。这两个对象的String类型,int类型属性都不相关,改变其中一个对象的值类型成员变量的具体值,另一个对象不会受影响。而这两个对象的Robert属性,分配的是同一个内存空间,一个改变,另一个肯定也会改变。

五、深复制详解

一种简单实现就是在clone方法中,对值类型的成员变量再次clone,但是值类型的成员变量必须实现Cloneable接口,覆盖Object的clone方法。这样对其它实体改动太大。

更好的方法是利用序列化和反序列化来实现深复制。

先将对象写到流里,然后再从流里读出对象。

将对象写到对象流里的前提是对象实现Serializable接口,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

具体实现:

package com.designpattern.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import com.designpattern.bean.Robot;

/**
 * 深复制
 *
 * @author chao
 *
 */
public class DeepClone implements Serializable {
	public Robot robot;
	public String name;
	public int number;

	public Object deepclone() {
		// 将对象写到流里
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		ObjectOutputStream oo;
		try {
			oo = new ObjectOutputStream(bo);
			oo.writeObject(this);
			// 从流里读出来
			ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
			ObjectInputStream oi = new ObjectInputStream(bi);
			return (oi.readObject());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public String toString() {
		return "     ShallowClone hashCode:" + hashCode() + " name:" + name + " number:" + number
				+ (robot == null ? "" : robot.toString());
	}
}

测试

package com.designpattern.prototype;

import com.designpattern.bean.Robot;
import com.designpattern.bean.Robot.Battery;

public class CloneTest {

	public static void main(String[] args) {

		testDeepClone();
	}

	private static void testDeepClone() {
		DeepClone deepClone = new DeepClone();
		deepClone.name = "1";
		deepClone.number = 1;
		deepClone.robot = new Robot();
		deepClone.robot.name = "1";
		deepClone.robot.battery = new Battery();
		deepClone.robot.battery.name = "1";
		System.out.println(deepClone.toString());
		DeepClone deepclone2 = (DeepClone) deepClone.deepclone();
		System.out.println(deepclone2.toString());
		deepClone.name = "2";
		deepClone.number = 2;
		deepClone.robot.name = "2";
		deepClone.robot.battery.name = "2";
		System.out.println(deepClone.toString());
		System.out.println(deepclone2.toString());

	}

	}
}

输出:

     ShallowClone hashCode:1704856573 name:1 number:1     Robot hashCode:705927765 name:1 age:0      Battery hashCode:366712642 name:1 level:0
     ShallowClone hashCode:1735600054 name:1 number:1     Robot hashCode:21685669 name:1 age:0      Battery hashCode:2133927002 name:1 level:0
     ShallowClone hashCode:1704856573 name:2 number:2     Robot hashCode:705927765 name:2 age:0      Battery hashCode:366712642 name:2 level:0
     ShallowClone hashCode:1735600054 name:1 number:1     Robot hashCode:21685669 name:1 age:0      Battery hashCode:2133927002 name:1 level:0

可以看到,深度复制的两个对象互不影响,所有属性都单独的分配了内存空间。没有相同的引用

六、JDK和ANDROIDSDK中的使用

JDK中体现:Object.clone;Cloneable

AndroidSDK中体现 Intent Parcelable

public class Intent implements android.os.Parcelable, Cloneable {
    @Override
    public Object clone() {
        return new Intent(this);
    }
 /**
     * Copy constructor.
     */
    public Intent(Intent o) {
        this.mAction = o.mAction;
        this.mData = o.mData;
        this.mType = o.mType;
        this.mPackage = o.mPackage;
        this.mComponent = o.mComponent;
        this.mFlags = o.mFlags;
        this.mContentUserHint = o.mContentUserHint;
        if (o.mCategories != null) {
            this.mCategories = new ArraySet<String>(o.mCategories);
        }
        if (o.mExtras != null) {
            this.mExtras = new Bundle(o.mExtras);
        }
        if (o.mSourceBounds != null) {
            this.mSourceBounds = new Rect(o.mSourceBounds);
        }
        if (o.mSelector != null) {
            this.mSelector = new Intent(o.mSelector);
        }
        if (o.mClipData != null) {
            this.mClipData = new ClipData(o.mClipData);
        }
    }

..........
}

搞懂原型模式,就很容易理解Intent传数据的时候什么情况下传的是引用,修改值会对原值造成影响。

相关代码github地址:https://github.com/robertjc/simpledesignpattern

不断完善中,有问题请多指教

欢迎扫描二维码,关注公众账号

时间: 2024-07-29 15:57:43

设计模式系列(二)原型模式的相关文章

设计模式系列之原型模式

prototype模式通过实例对象指定需要创建的类型,这与上一篇我们提到的factory method模式有本质不同,factory method模式是通过类的继承定义不同子类来达到创建不同类型对象的目的,属于类模式,prototype模式通过调用组合的对象成员生成不同类型的对象实例,属于对象模式. 由于这个特性,prototype具有以下适用场合: · 需要运行时确定实例化的类时,比如动态装载库时 · 避免创建过多子类时.子类太多永远是不受欢迎的,在factory method中我们也提到通过

设计模式系列二(策略者模式)

浑浑噩噩的过的漫无目的,更多的是迷茫,真不知该如何定位自己的人生?空有远大抱负,而又力不从心!有句话说的好,当你的才能撑不起你的野心的时候,就该静下来心来好好学习了!于是闲来无事,便继续开始我的设计模式之游!今天便研究下策略者模式! 1.策略者模式解析 大话设计模式是这样讲道: 策略者模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法减少各种算法类与使用算法类之间的耦合[DPE]. 个人理解:所谓一系列算法方法就是一系列

设计模式学习05—原型模式

一.动机与定义 之前学习原型模式一直以为原型模式目的是为了方便的创建相同或相似对象,用复制对象的方式替换new的方式,还研究了深克隆和浅克隆.最近仔细看了GOF的设计模式,发现原型模式的本意并不仅仅是复制对象这么简单. 复制对象确实是一方面,当我们需要大量相似,甚至相同对象的时候,除了一个个的new之外,还可以根据一个原型,直接复制出更多的对象.但是如果把原型模式认为只是复制对象这么简单就错了. 创建型模式主要讲如何创建对象,通常包含何时创建,谁来创建,怎么创建等.GOF书里面写的意图是,用原型

Java描述设计模式(05):原型模式

一.原型模式简介 1.基础概念 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象. 2.模式结构 原型模式要求对象实现一个可以"克隆"自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例.这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建. 3.代码实现 1).UML关系图 Java描述设计模

java设计模式 GOF23 04 原型模式

一.原型模式介绍 因为java中new一个新对象比clone一个对象需要花费等多的资源,所以一般需要 在短时间内创建大量对象并且new对象的过程需要耗费比较多的资源使用原型模式. 想要clone一个类需要这个类实现Cloneable接口,重载clone方法,这个接口在底层 通过内存拷贝实现clone对象,因此效率很高. package com.lz.prototype; import java.util.Date; public class ShallowClone implements Clo

[js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表

所谓组合模式,就是把一堆结构分解出来,组成在一起,现实中很多这样的例子,如: 1.肯德基套餐就是一种组合模式, 比如鸡腿堡套餐,一般是是由一个鸡腿堡,一包薯条,一杯可乐等组成的 2.组装的台式机同理,由主板,电源,内存条,显卡, 机箱,显示器,外设等组成的 把一个成型的产品组成部件,分成一个个独立的部件,这种方式可以做出很多灵活的产品,这就是组合模式的优势 比如:家用台式机电脑,要求配置比较低, 这个时候只需要主板+电源+内存条+机箱+显示器+外设就可以了,不需要配置独立显卡 鸡腿堡+鸡翅+紫薯

设计模式系列之工厂模式

设计模式一直是面向对象软件设计中最重要的一个领域,围绕设计模式讨论的话题也是数不胜数,其中GOF代表的23种设计模式更是经典之著.这个系列中我将会从自己的理解出发,阐述每种设计模式的思想,作用和利弊. 一. 设计模式概念 要讲解设计模式,必然先要说清楚两个问题, 1.什么是设计模式? 2.为什么需要设计模式? 对于设计模式,GOF是这么定义的:设计模式是对被用来在特定场景下解决一般设计问题的类和相互通信的对象的描述,更特殊地,将之放到面向对象软件设计中来讲,设计模式可以被认为是实践中总结出的设计

从王者荣耀看设计模式(十七.原型模式)

从王者荣耀看设计模式(原型模式) 一.简介 王者荣耀包含有很多的玩法,其中有一种游戏模式只在周六和周日开放,那就是--克隆模式.与常规的游戏双方阵营只允许出现单一英雄不同,在克隆模式中,双方各选择一个英雄进行克隆,换句话说,一个阵营的五个人操作的五个相同的英雄 二.模式动机 在软件系统中,有些对象的创建过程比较复杂,而且有时候需要频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在. 三.原型模式 原型模式

php设计模式 四 (观察者 原型模式 迭代器模式)

观察者模式 观察者模式(有时又被称为发布-订阅Subscribe>模式.模型-视图View>模式.源-收听者Listener>模式或从属者模式)是软件设计模式的一种.在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知.这通常透过呼叫各观察者所提供的方法来实现.此种模式通常被用来实现事件处理系统. 当一个对象的状态发生改变时,依赖他的对象全部会接到通知,并自动更新.观察者模式实现了低耦合 非入侵式的通知与更新机制. 观察者模式示例: 首先创建一个事

Android设计模式系列--工厂方法模式

工厂方法模式,往往是设计模式初学者入门的模式,的确,有人称之为最为典型最具启发效果的模式.android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具管理类.今天以ThreadFactory举例说明一下简单工厂模式和工厂方法模式. 工厂方法模式,Factory Method,简单的方式,不简单的应用. 1.意图定义一个用于创建对象的接口,让子类决定实例化哪个类.工厂方式模式使一个类的实例化延迟到其子类.热门词汇:虚构造器 延迟 创建对象 子类 2