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