快速造汽车----原型模式
产汽车很累怎么办?
上一次我们介绍了工厂模式(Factory),即用户可以通过提供具体的车型信息由工厂生产出来返回。
后来竟然发现客户越来越少,工厂也入不敷出,甚至遭到了投诉,口碑极差,即将砸大门倒闭,这是为啥了呢?奥,原来是工厂产汽车太慢了,豪门大佬一下子要100台劳斯莱斯,我们工人不断从零做起,购买零件,组装轮胎、组装车身、组装发动机…
高工程师来帮忙
组装的太慢了,这时高工程师就想,如果我们此时有一台劳斯莱斯,能够不断拷贝出来新的劳斯莱斯就好了,但是拷贝是需要new出来的,然后不断设计添加属性、进行组装的,这是高工程师拿出了法宝Cloneable接口,只要是实现了此接口的类,均可以拷贝出来同样的新的劳斯莱斯车!!很快,工厂再次站了起来,高工程师也破格升职为高高工程师~~~
哈哈哈,这就是设计模式中原型模式的具体抽象!!!
高工程师的法宝(实现原型模式)
图解法宝(原型模式)
这时,问题就明白了,我们需要这样拯救工厂:
- 我们来设计一个车型,除下设计此车型的所有制作流程以外,我们需要对此车型类实现Cloneable接口、覆写clone()方法。
- 生产新的车子时,只需要调用已创建好的车型的clone()方法,造新车即可!!!
高工程师的最初具体实现(浅拷贝)
劳斯莱斯的车型类
package com.design_patterns.prototype.instance;
import com.design_patterns.factory.instance.Car;
public class RollsRoyce implements Car, Cloneable {
private String tirName = null; //轮胎型号
private String bodyName = null; //车身型号
private String engineName = null; //发动机型号
private Information information = null; //劳斯莱斯车的信息类对象
public String getTirName() {
return tirName;
}
public void setTirName(String tirName) {
this.tirName = tirName;
}
public String getBodyName() {
return bodyName;
}
public void setBodyName(String bodyName) {
this.bodyName = bodyName;
}
public String getEngineName() {
return engineName;
}
public void setEngineName(String engineName) {
this.engineName = engineName;
}
public Information getInformation() {
return information;
}
public void setInformation(Information information) {
this.information = information;
}
@Override
public void produce() {
System.out.println("劳斯莱斯车生产成功!");
}
/**
* 覆写劳斯莱斯车的拷贝方法,默认为父类的clone方法
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "RollsRoyce{" +
"tirName='" + tirName + '\'' +
", bodyName='" + bodyName + '\'' +
", engineName='" + engineName + '\'' +
", information=" + information +
'}';
}
}
劳斯莱斯车的生产信息类Information(表示第几辆车)
package com.design_patterns.prototype.instance;
public class Information {
private static int amount = 0; //劳斯莱斯车的生产数量
public Information(){
amount++;
}
public static int getAmount() {
return amount;
}
public static void setAmount(int amount) {
Information.amount = amount;
}
@Override
public String toString() {
return "劳斯莱斯@num" + amount;
}
}
生产操作测试类
package com.design_patterns.prototype.instance;
public class Client {
public static void main(String[] args) throws Exception{
RollsRoyce rollsRoyce = new RollsRoyce();
rollsRoyce.setTirName("劳斯莱斯轮胎"); //制造轮胎
rollsRoyce.setBodyName("劳斯莱斯车身"); //制造车身
rollsRoyce.setEngineName("劳斯莱斯发动机"); //制造发动机
rollsRoyce.produce(); //制造汽车,此为汽车的制作全部过程
rollsRoyce.setInformation(new Information());
System.out.println("样本车产生---->" + rollsRoyce + "\n");
int num = 50;
RollsRoyce rollsRoyce1 = null;
while (num > 0){
//生产50辆劳斯莱斯车
rollsRoyce1 = (RollsRoyce) rollsRoyce.clone();
System.out.println(rollsRoyce1);
System.out.println("生产编号: " + rollsRoyce1.hashCode());
num--;
}
}
}
运行结果
劳斯莱斯车生产成功!
样本车产生---->RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num1}
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num1}
生产编号: 1163157884
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num1}
生产编号: 1956725890
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num1}
生产编号: 356573597
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num1}
生产编号: 1735600054
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num1}
生产编号: 21685669
......
由于生产50台,数据过多暂列举一部分,生产编号均不同
哇塞,此时我们发现,完全相同的50太劳斯莱斯车几乎瞬间被生产出来了,再也不用辛辛苦苦set、set、set的生产了,生产效率得到了极大的提升,正当老板和客户十分高兴的时候。
高工程师对老板说,这50台劳斯莱斯不能出售了,为了日后工厂的正向发展,必须销毁,这是为啥呢?这时都注意到了劳斯莱斯车车内玻璃窗都统一印着一行小字: information: 劳斯莱斯@num1,为什么车型的编号的都是1呢?明明确定了信息类在实例化时acount都会累加的。
此时高工程师说,事实上我们只有一个Information实例。我们在拷贝劳斯莱斯车的时候使用的是浅拷贝,而Information类为引用数据类型,浅拷贝只能将新的引用数据类型的取值指向原引用数据的地址,不能够重新生产(new)引用数据类型。如果要想实现也生产(new)引用数据类型Information,则必须改进覆写clone()方法,高工程师给出了解决方案…
新的解决方案
高工程师给出了指导方案,将(RollsRoyce类):
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
改进为
@Override protected Object clone() throws CloneNotSupportedException { RollsRoyce rollsRoyce = (RollsRoyce) super.clone(); rollsRoyce.information = new Information(); //实例化一个新的Information类对象 return rollsRoyce; //返回深拷贝后的劳斯莱斯车对象 }
这样就对Information劳斯莱斯车信息的类也进行了生产,再次运行生产劳斯莱斯车的操作…
运行结果
劳斯莱斯车生产成功!
样本车产生---->RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num1}
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num2}
生产编号: 1163157884
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num3}
生产编号: 1956725890
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num4}
生产编号: 356573597
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num5}
生产编号: 1735600054
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num6}
生产编号: 21685669
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num7}
生产编号: 2133927002
RollsRoyce{
tirName='劳斯莱斯轮胎', bodyName='劳斯莱斯车身', engineName='劳斯莱斯发动机', information=劳斯莱斯@num8}
生产编号: 1836019240
......
由于生产50台,数据过多暂列举一部分,生产编号均不同,information属性也不同
总结
突发奇想,嘻嘻,第一次使用这种举例的口吻写笔记,不知道效果好不好,实际上本章也是简单的介绍了原型模式的基本使用方式,以及浅拷贝与深拷贝、深拷贝建议使用对象序列化实现(这篇文章有序列化实现深拷贝的方法)。
如果小伙伴们感觉写的还不错,麻烦随手给点个赞,嘿嘿,如果感觉写的不好也请私信我,我好改正,加油冲冲冲!
高工程师已经升为高高工程师了,他的路还要走多长呢?