设计模式学习笔记05 - Java版之原型模式

1. 克隆羊问题

克隆三个一模一样的羊, 代码如下:

package com.liyang;

public class Sheep {
	private String name;
	private int age;
	private String color;
	
	public Sheep() {
		super();
	}

	public Sheep(String name, int age, String color) {
		super();
		this.name = name;
		this.age = age;
		this.color = color;
	}

	@Override
	public String toString() {
		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
	}

	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 String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}
	
}
package com.liyang;

public class Client {

	public static void main(String[] args) {
		Sheep sheep = new Sheep("tom", 1, "白色");
		Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
		Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
		System.out.println(sheep);
		System.out.println(sheep2);
		System.out.println(sheep3);
	}

}

优点: 容易理解, 简单易操作
缺点: 创建对象时, 总是需要获取原始对象的属性, 如果创建对象比较复杂则效率低
总是需要重新初始化对象, 而不是动态获取对象运行时状态, 不够灵活

改进: Object类中有一个clone()的方法, 该方法可以将Java对象复制一份, 但是需要Java类必须实现一个接口Cloneable, 该接口表示该类能够复制并有复制能力 => 原型模式

2. 基本介绍

  1. 原型模式是指: 用原型实例指定创建对象的种类, 并且通过拷贝这些原型创在新的对象
  2. 原型模式是一种创建型设计模式, 允许一个对象可创建另一个可定制的对象, 无需知道细节
  3. 工作原理: 通过将一个原型对象传给那个要发动创建的对象, 这个要发动创建的对象通过请求原型对象拷贝他们自己来实施创建 即对象.clone()
  4. 孙悟空拔出猴毛, 变出其他的孙悟空…
    在这里插入图片描述

客户(Client)角色:客户类提出创建对象的请求;

抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或者Java抽象类实现。此角色定义了的具体原型类所需的实现的方法。

具体原型(Concrete Prototype)角色:此角色需要实现抽象原型角色要求的克隆相关的接口。

package com.liyang;

public class Sheep implements Cloneable {
	private String name;
	private int age;
	private String color;
	
	public Sheep() {
		super();
	}

	public Sheep(String name, int age, String color) {
		super();
		this.name = name;
		this.age = age;
		this.color = color;
	}

	@Override
	public String toString() {
		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
	}

	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 String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Sheep sheep = null;
		sheep = (Sheep)super.clone();
		return sheep;
	}
	
}
package com.liyang;

public class Client {

	public static void main(String[] args) throws CloneNotSupportedException {
		Sheep sheep = new Sheep("tom", 1, "白色");
		Sheep sheep2 = (Sheep)sheep.clone();
		System.out.println(sheep);
		System.out.println(sheep2);
	}

}

这样子使用原型模式, 一旦我们的Sheep类增加或者减少了属性, 我们不需要做任何变化…

3. 浅拷贝和深拷贝

3.1 浅拷贝

  1. 对于数据类型是进本数据类型的成员变量, 浅拷贝会直接进行值传递, 也就是将属性值复制一份给新的对象
  2. 对于数据类型是引用数据类型的成员变量, 比如说是数组 类的对象, 那么浅拷贝就会进行引用传递, 也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象. 这样子实际上他们两个是指向同一个实例, 那么我们一旦修改其中一个, 另外一个也会跟着发生变化…
  3. 默认的clone方法是浅拷贝

3.2 深拷贝

  1. 复制所有基本数据类型
  2. 为对象的引用数据类型申请存储空间, 并复制, 直到该对象可达所有的对象
  3. 重写clone方法实现深拷贝
  4. 通过对象序列化实现深拷贝

3.2.1 方式一 (Cloneable接口实现)

package com.liyang;

public class SheepTarget implements Cloneable {
	private String name;
	private int age;

	public SheepTarget() {
		super();
	}

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

	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;
	}

	@Override
	public String toString() {
		return "SheepTarget [name=" + name + ", age=" + age + "]";
	}

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

}
package com.liyang;

public class Sheep implements Cloneable {
	private String name;
	private int age;
	private String color;
	public SheepTarget friends;

	public SheepTarget getFriends() {
		return friends;
	}

	public void setFriends(SheepTarget friends) {
		this.friends = friends;
	}

	public Sheep() {
		super();
	}

	public Sheep(String name, int age, String color) {
		super();
		this.name = name;
		this.age = age;
		this.color = color;
	}

	@Override
	public String toString() {
		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", friends=" + friends + "]";
	}

	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 String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object object = null;
		// 拷贝基本数据类型
		object = super.clone();
		// 拷贝引用
		Sheep sheep = (Sheep) object;
		sheep.friends = (SheepTarget) friends.clone();
		return sheep;
	}

}
package com.liyang;

public class Client {

	public static void main(String[] args) throws CloneNotSupportedException {
		Sheep sheep = new Sheep("tom", 1, "白色");
		sheep.setFriends(new SheepTarget("aa", 1));
		Sheep sheep2 = (Sheep) sheep.clone();
		System.out.println(sheep.friends.hashCode());
		System.out.println(sheep2.friends.hashCode());
	}

}

3.2.2 方式二 (通过对象序列化实现)

package com.liyang;

import java.io.Serializable;

public class SheepTarget implements Serializable{
	private String name;
	private int age;

	public SheepTarget() {
		super();
	}

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

	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;
	}

	@Override
	public String toString() {
		return "SheepTarget [name=" + name + ", age=" + age + "]";
	}

}
package com.liyang;

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

public class Sheep implements Serializable {
	private String name;
	private int age;
	private String color;
	public SheepTarget friends;

	public SheepTarget getFriends() {
		return friends;
	}

	public void setFriends(SheepTarget friends) {
		this.friends = friends;
	}

	public Sheep() {
		super();
	}

	public Sheep(String name, int age, String color) {
		super();
		this.name = name;
		this.age = age;
		this.color = color;
	}

	@Override
	public String toString() {
		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", friends=" + friends + "]";
	}

	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 String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public 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);
			Sheep sheep = (Sheep)ois.readObject();
			
			return sheep;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			try {
				// 关闭流
				bos.close();
				oos.close();
				bis.close();
				ois.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
		
	}

}
package com.liyang;

public class Client {

	public static void main(String[] args) throws CloneNotSupportedException {
		Sheep sheep = new Sheep("tom", 1, "白色");
		sheep.setFriends(new SheepTarget("aa", 1));
		Sheep sheep2 = (Sheep)sheep.deepClone();
		System.out.println(sheep.friends.hashCode());
		System.out.println(sheep2.friends.hashCode());
	}

}

4. 注意事项

  1. 创建对象比较复杂, 可以利用原型模式来简化创建过程, 同时能提高效率
  2. 不用重新初始化对象, 而是动态获取对象运行时的状态
  3. 如果原始对象发生变化(增加或者减少属性), 其他的克隆对象也会发生相应的变化, 无需修改代码
  4. 实现深拷贝需要比较复杂代码
  5. 缺点: 每个类需要一个clone方法, 这样对已有的类进行改造违背了ocp原则
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值