设计模式22-原型模式

1.场景问题解决

1.1 场景描述

电子账单项目遇到的问题:银行的电子账单、广告信:
特点:量大、时间要求紧,在电子账单内容生成后,快速发送成功.

1.2 OO设计

多线程实现

  • EventTemplate 为公用对象
public class EventTemplate {
	private String eventSubject, eventContent;

	public EventTemplate(String eventSubject, String eventContent) {
		this.eventSubject = eventSubject;
		this.eventContent = eventContent;
	}

	public String geteventSubject() {
		return eventSubject;
	}

	public String geteventContent() {
		return eventContent;
	}
}

  • oo 为oo设计时的
    • Mail 邮件对象
    • MainOOTest 测试类

public class Mail {
	private String receiver;
	private String subject;
	private String content;
	private String tail;

	public Mail(EventTemplate et) {
		this.tail = et.geteventContent();
		this.subject = et.geteventSubject();
	}

	public String getReceiver() {
		return receiver;
	}

	public void setReceiver(String receiver) {
		this.receiver = receiver;
	}

	public String getSubject() {
		return subject;
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getContent() {
		return content;
	}

	public String getTail() {
		return tail;
	}

	public void setTail(String tail) {
		this.tail = tail;
	}

}



public class MainOOTest {
	public static void main(String[] args) {
		int i = 0;
		int MAX_COUNT = 10;
		EventTemplate et = new EventTemplate("9月份信用卡账单", "国庆抽奖活动...");

		Mail mail = new Mail(et);

		while (i < MAX_COUNT) {
			// 以下是每封邮件不同的地方
			
			mail.setContent(getRandString(5) + ",先生(女士):你的信用卡账单..."
					+ mail.getTail());
			mail.setReceiver(getRandString(5) + "@" + getRandString(8) + ".com");
			// 然后发送邮件
			sendMail(mail);
			i++;
		}

	}

	public static String getRandString(int maxLength) {
		String source = "abcdefghijklmnopqrskuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
		StringBuffer sb = new StringBuffer();
		Random rand = new Random();
		for (int i = 0; i < maxLength; i++) {
			sb.append(source.charAt(rand.nextInt(source.length())));
		}
		return sb.toString();
	}

	public static void sendMail(Mail mail) {
		System.out.println("标题:" + mail.getSubject() + "\t收件人:"
				+ mail.getReceiver() + "\t内容:" + mail.getContent()
				+ "\t....发送成功!");
	}

}

1.3 需求变动

1.4 带来问题

2.用设计模式改进

2.1 分析

2.2 重新设计

[外链图片转存失败(img-KDroX7GA-1568906631790)(https://raw.githubusercontent.com/bobshute/public/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/22%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F-1.png)]

2.3 源码

  • EventTemplate 为公用对象
public class EventTemplate {
	private String eventSubject, eventContent;

	public EventTemplate(String eventSubject, String eventContent) {
		this.eventSubject = eventSubject;
		this.eventContent = eventContent;
	}

	public String geteventSubject() {
		return eventSubject;
	}

	public String geteventContent() {
		return eventContent;
	}
}

  • proto 为原型设计模式时
    • Mail 邮件对象
    • MainProtoTest 测试类

public class Mail implements Cloneable {
	private String receiver;
	private String subject;
	private String content;
	private String tail;
	//如果有一个ArrayList
	private ArrayList<String> arrayList;
	public Mail(EventTemplate et) {
		this.tail = et.geteventContent();
		this.subject = et.geteventSubject();
	}

	@Override
	public Mail clone() {
		Mail mail = null;
		try {
			mail = (Mail) super.clone();
			//对象的默认copy时arrayList的是引用,所以需要用下面的方式再copy才是clone的值(独立的区域)
			mail.arrayList = (ArrayList<String>)this.arrayList.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return mail;
	}

	public String getReceiver() {
		return receiver;
	}

	public void setReceiver(String receiver) {
		this.receiver = receiver;
	}

	public String getSubject() {
		return subject;
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getContent() {
		return content;
	}

	public String getTail() {
		return tail;
	}

	public void setTail(String tail) {
		this.tail = tail;
	}

}



public class MainProtoTest {
	public static void main(String[] args) {
		int i = 0;
		int MAX_COUNT = 10;
		EventTemplate et = new EventTemplate("9月份信用卡账单", "国庆抽奖活动...");

		Mail mail = new Mail(et);

		while (i < MAX_COUNT) {
			// 以下是每封邮件不同的地方
			Mail cloneMail = mail.clone();
			cloneMail.setContent(getRandString(5) + ",先生(女士):你的信用卡账单..."
					+ mail.getTail());
			cloneMail.setReceiver(getRandString(5) + "@" + getRandString(8)
					+ ".com");
			// 然后发送邮件
			sendMail(cloneMail);
			i++;
		}

	}

	public static String getRandString(int maxLength) {
		String source = "abcdefghijklmnopqrskuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
		StringBuffer sb = new StringBuffer();
		Random rand = new Random();
		for (int i = 0; i < maxLength; i++) {
			sb.append(source.charAt(rand.nextInt(source.length())));
		}
		return sb.toString();
	}

	public static void sendMail(Mail mail) {
		System.out.println("标题:" + mail.getSubject() + "\t收件人:"
				+ mail.getReceiver() + "\t内容:" + mail.getContent()
				+ "\t....发送成功!");
	}

}

3.设计模式总结

3.1 定义

原型模式:通过复制现有实例来创建新的实例,无须知道相应类的信息

3.2 分析思路

[外链图片转存失败(img-N95QOBtp-1568906631792)(https://raw.githubusercontent.com/bobshute/public/master/imgs/csdn/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/22%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F-2.png)]

3.3 优缺点

  • 优点:
    使用原型模式创建对象比直接new一个对象更有效
    隐藏制造新实例的复杂性
    重复地创建相似对象时可以考虑使用原型模式
  • 缺点:
    每一个类必须配备一个克隆方法
    深层复制比较复杂

4. 设计模式使用场景及注意

4.1 使用场景

  • 复制对象的结构与数据
  • 希望对目标对象的修改不影响既有的原型对象
  • 创建对象成本较大的情况下

4.2 注意

  • 使用原型模式复制对象不会调用类的构造方法。所以,单例模式与原型模式是冲突的,在使用时要特别注意。(单例模式不能用clone)
  • 不用用final 对象
  • Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

5.参考文章

内容总计于HeadFirst设计模式及相关视频

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章