通过复制生成实例
适用条件
(1) 对象种类繁多,无法将他们整合到一个类中
(2) 难以根据类生成实例
生成实例的过程过于复杂,很难根据类来生成实例
(3) 想解耦框架与生成的实例
生成实例的框架不依赖具体类,不能通过类名来生成实例,可以实现“注册”一个原型实例
参与角色
- Prototype:定义用于复制现有实例来生成新实例的方法
- ConcretePrototype:实现复制现有实例并生成新实例的方法
- Client
UML
示例代码
发邮件为例子,假如需要给多人发邮件,邮件内容一样,接收人不一致。
Mail
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Data public class Mail implements Cloneable {
private String content; private String receiver;
public Mail(String content) { this.content = content; }
@Override protected Mail clone() { Mail mail = null; try { mail = (Mail) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return mail; } }
|
Main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Main { public static void main(String[] args) { Mail mail = new Mail("邮件内容都是一样的");
for (int i = 0; i < 10; i++) { mail.setReceiver("user" + i); sendMail(mail); } } public static void sendMail(Mail mail) { String msg = String.format("内容:%s 收件人%s", mail.getContent(), mail.getReceiver()); System.out.println(msg); } }
|
运行结果如下:
1 2 3 4 5 6 7 8 9 10
| 内容:邮件内容都是一样的 收件人user0 内容:邮件内容都是一样的 收件人user1 内容:邮件内容都是一样的 收件人user2 内容:邮件内容都是一样的 收件人user3 内容:邮件内容都是一样的 收件人user4 内容:邮件内容都是一样的 收件人user5 内容:邮件内容都是一样的 收件人user6 内容:邮件内容都是一样的 收件人user7 内容:邮件内容都是一样的 收件人user8 内容:邮件内容都是一样的 收件人user9
|
这是一个单线程没有问题,假如发送一次时间0.02s, 600万封邮件需要33小时,也就是一整天也发不完,ok我们把sendMail方法更改为多线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Main { public static void main(String[] args) { Mail mail = new Mail("邮件内容都是一样的");
for (int i = 0; i < 10; i++) { mail.setReceiver("user" + i); sendMailThread(mail); } }
public static void sendMail(Mail mail) { String msg = String.format("内容:%s 收件人%s", mail.getContent(), mail.getReceiver()); System.out.println(msg); }
public static void sendMailThread(Mail mail) { new Thread(() -> sendMail(mail)).start(); } }
|
运行结果如下:
1 2 3 4 5 6 7 8 9 10
| 内容:邮件内容都是一样的 收件人user2 内容:邮件内容都是一样的 收件人user2 内容:邮件内容都是一样的 收件人user5 内容:邮件内容都是一样的 收件人user6 内容:邮件内容都是一样的 收件人user3 内容:邮件内容都是一样的 收件人user9 内容:邮件内容都是一样的 收件人user7 内容:邮件内容都是一样的 收件人user9 内容:邮件内容都是一样的 收件人user8 内容:邮件内容都是一样的 收件人user5
|
问题出现了,当上一个线程还没有发送完成,下一个线程直接就把接收人更改了,线程不安全了(当然你有N种方法解决线程安全),但是我们这里用Prototype设计模式来解决。
原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多
1 2 3 4 5
| for (int i = 0; i < 10; i++) { Mail cloneMail = mail.clone(); cloneMail.setReceiver("user" + i); sendMailThread(cloneMail); }
|
云行结果如下:
1 2 3 4 5 6 7 8 9 10
| 内容:邮件内容都是一样的 收件人user7 内容:邮件内容都是一样的 收件人user2 内容:邮件内容都是一样的 收件人user1 内容:邮件内容都是一样的 收件人user8 内容:邮件内容都是一样的 收件人user6 内容:邮件内容都是一样的 收件人user4 内容:邮件内容都是一样的 收件人user3 内容:邮件内容都是一样的 收件人user0 内容:邮件内容都是一样的 收件人user5 内容:邮件内容都是一样的 收件人user9
|
注意事项