本文会介绍一下原型模式和享元模式
放在一起介绍是觉得它们有一点相似之处
原型模式:提供对象的一个拷贝,也就是clone。有深克隆和浅克隆两种。
享元模式:在享元工厂类存储着享元类的多个对象,每次使用享元类的对象时,返回享元工厂类中的一个结果即可。
1)原型模式
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
2)享元模式
运用共享技术有效的支持大量细粒度对象的复用。
通过clone()出来的两个对象是不在同一块地址空间的,
B = A.clone();
B == A is false
1)浅克隆
在浅克隆中,被复制对象的所有普通成员变量都具有与原来的对象相同的值,而所有的对其它对象的引用仍然指向原来的对象。
如果复制出来一个新对象,那么新对象跟旧对象里面的引用对象是指向用一片地址空间的。
2)深克隆
深克隆把要复制的对象中所引用的对象都复制了一遍,新对象跟旧对象里面的引用成员变量是指向不同的堆的
由于邮件对象包含的内容较多,某系统中需要提供一个邮件复制功能,对于已经复制好的邮件对象,可以通过复制的方法创建一个新的邮件对象,如果需要改变某部分内容,只需要修改复制后的对象。
现用浅克隆实现复制邮件(E-mail)的同时不复制附件(Attachment)
用深克隆实现复制邮件(E-mail)的同时复制附件(Attachment)
public class EmailTint implements Cloneable{
private Attachment attachment;
public EmailTint() {
this.attachment = new Attachment();
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Attachment getAttachment() {
return this.attachment;
}
public void display() {
System.out.println("查看邮件");
}
}
//作为邮件类里面的引用对象
public class Attachment {
public void download() {
System.out.println("下载附件...");
}
}
public class PrototypeDemo {
public static void main(String[] args) throws CloneNotSupportedException {
EmailTint emailTint, copyEmailTint;
emailTint = new EmailTint();
copyEmailTint = (EmailTint) emailTint.clone();
System.out.println(emailTint);//在不同的地址空间
System.out.println(copyEmailTint);//在不同的地址空间
System.out.print("emailTint == copyEmailTint : ");
System.out.println(emailTint == copyEmailTint);//false
System.out.print("emailTint.getAttachment() == copyEmailTint.getAttachment() : ");
System.out.println(emailTint.getAttachment() == copyEmailTint.getAttachment());//true
}
}
2)深克隆
深克隆借助序列化操作,将对象写入流中再读出
注意:此时原型类跟原型类里面的引用对象类都要实现Serializable接口。
为了区分两个模式,深克隆调用的是deepClone,也可以同时实现Serializable、Cloneable,并实现clone方法
public class EmailDeep implements Serializable {
private Attachment attachment;
public EmailDeep() {
this.attachment = new Attachment();
}
public Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
//将对象写入流中
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Object o = ois.readObject();
return o;
}
public Attachment getAttachment() {
return this.attachment;
}
public void display() {
System.out.println("查看邮件");
}
}
public class Attachment implements Serializable {
public void download() {
System.out.println("下载附件...");
}
}
public class PrototypeDemo {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
EmailDeep emailDeep, emailDeepCopy;
emailDeep = new EmailDeep();
emailDeepCopy = (EmailDeep) emailDeep.deepClone();
System.out.print("emailDeep == emailDeepCopy : ");
System.out.println(emailDeep == emailDeepCopy);//false
System.out.print("emailDeep.getAttachment() == emailDeepCopy.getAttachment() : ");
System.out.println(emailDeep.getAttachment() == emailDeepCopy.getAttachment());//false
}
}
很多网络设备都支持共享,多台计算机终端可以连接同一台网络设备,并通过该设备进行网络通信。使用享元模式对该网络设备进行共享。
interface NetworkDevice {
String getType();
void use();
}
public class Switch implements NetworkDevice{
private String type;
public Switch(String type) {
this.type = type;
}
@Override
public String getType() {
return this.type;
}
@Override
public void use() {
System.out.println("使用" + this.type + "~");
}
}
public class Hub implements NetworkDevice{
private String type;
public Hub(String type) {
this.type = type;
}
@Override
public String getType() {
return this.type;
}
@Override
public void use() {
System.out.println("使用" + this.type + "~");
}
}
public class DeviceFactory {
//享元池
private ArrayList<NetworkDevice> devices = new ArrayList<>();
private int totalTerminal = 0;
public DeviceFactory() {
//享元对象,随着系统的启动只有这两个
devices.add(new Switch("Cisco-WS-C2904-24"));
devices.add(new Hub("TP-LINK-F848"));
}
public NetworkDevice getDeviceFactory(String type) {
if (type.equalsIgnoreCase("cisco")) {
++totalTerminal;
//返回其中一个享元对象
return devices.get(0);
} else if (type.equalsIgnoreCase("tp")) {
++totalTerminal;
//返回另一个
return devices.get(1);
} else {
System.out.println("不匹配!");
return null;
}
}
public int getTotalTerminal() {
return totalTerminal;
}
public int getDevices() {
return devices.size();
}
@Override
public String toString() {
StringBuilder sbr = new StringBuilder();
for (NetworkDevice device : devices){
sbr.append(device.getType()).append("\n");
}
return sbr.toString().trim();
}
}
public class FlyweightDemo {
public static void main(String[] args) {
NetworkDevice nd1, nd2, nd3, nd4, nd5;
DeviceFactory deviceFactory = new DeviceFactory();
System.out.println("======================");
nd1 = deviceFactory.getDeviceFactory("cisco");
System.out.println(nd1.getType());
nd1.use();
System.out.println("======================");
nd2 = deviceFactory.getDeviceFactory("cisco");
System.out.println(nd2.getType());
nd2.use();
System.out.println("======================");
nd3 = deviceFactory.getDeviceFactory("tp");
System.out.println(nd3.getType());
nd3.use();
System.out.println("======================");
nd4 = deviceFactory.getDeviceFactory("cisco");
System.out.println(nd4.getType());
nd4.use();
System.out.println("======================");
nd5 = deviceFactory.getDeviceFactory("tp");
System.out.println(nd5.getType());
nd5.use();
System.out.println("======================");
System.out.println("提供对象数目:"+deviceFactory.getTotalTerminal());
System.out.println("已有对象种类:"+deviceFactory.getDevices());
System.out.println(deviceFactory);
System.out.println("======================");
}
}