設計模式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設計模式及相關視頻

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