转自:设计模式是什么鬼(原型)

原型(Prototype)是什么意思?工业生产中通常是指在量产之前研发出的概念实现,如果可行性满足即可参照原型进行量产。有人说了,那不就是印章?其实这并不怎么贴切,印章并不是最终实例,我更愿意称其为“类”!

呃……僵尸脸花泽类经世名言:想哭的时候就道理,这样眼泪就不会流出来了。(尼玛,都流脑子里了吧!)

言归正传,大家一定见过这种印章吧,就是皮带轮可以转动,可随意调整成自己需要的文字,其实跟我们的四大发明活字印刷同出一辙,我们填完表格签好字,行政人员拿这个往上一盖,一个日期便出现在落款出。

其实当行政人员调整好了文字,照纸上盖下去那一刹那,其实就类似于实例化的过程了,new Stamp();每个盖出的印都可以不一样,例如我们更换了日期,那么每天都有不同日期的实例了,那有人意识到了,同一天的那些实例们,其实是完全一模一样的实例拷贝,那这就比较麻烦,每个文档都要用章子(类)去盖(实例化)一下。

好了,让我们忘掉盖章实例化模式吧。通常我们都是怎样做协议书的呢?搞一个Word文档吧,写好后复制给别人修改就好了。

注意了,行政人员要新建一个word文档了,这个过程其实是在实例化,我们暂且叫它“零号”文件,那当写好了文档后,把这个文件复制给其他公司员工去填写,那么这个零号文件我们就称之为“原型”。

想必我们已经搞明白了,原型模式,实际上是从原型实例复制克隆出新实例,而绝不是从类去实例化,这个过程的区别一定要搞清楚!OK,那开始我们的实战部分。

假设我们要做一个打飞机游戏,游戏设定位纵版移动,单打。

既然是单打,那我们的主角飞机当然只有一架,于是我们写一个单例模式(设计模式是什么鬼(单例)),此处我们省略主角代码。那么敌机呢?当然有很多架了,好,为了说明问题我们去繁就简,先写一个敌机类。

public class EnemyPlane {private int x;//敌机横坐标private int y = 0;//敌机纵坐标public EnemyPlane(int x) {//构造器this.x = x;}public int getX() {return x;}public int getY() {return y;}public void fly(){//让敌机飞y++;//每调用一次,敌机飞行时纵坐标+1}
}

代码第5行,初始化只接收x坐标,因为敌机一开始是从顶部出来所以纵坐标y必然是0。此类只提供getter而没有setter,也就是说只能在初始化时确定敌机的横坐标x,后续是不需要更改坐标了,只要连续调用第17行的fly方法即可让飞机跟雨点一样往下砸。

好了,我们开始绘制敌机动画了,先实例化出50架吧。

public class Client {public static void main(String[] args) {List<EnemyPlane> enemyPlanes = new ArrayList<EnemyPlane>();for (int i = 0; i < 50; i++) {//此处随机位置产生敌机EnemyPlane ep = new EnemyPlane(new Random().nextInt(200));enemyPlanes.add(ep);}}
}

注意代码第7行,觉不觉得每个迭代都实例化new出一个对象存在性能问题呢?答案是肯定的,这个实例化的过程是得不偿失的,构造方法会被调用50次,cpu被极大浪费了,内存被极大浪费了,尤其对于游戏来说性能瓶颈绝对是大忌,这会造成用户体验问题,谁也不希望玩游戏会卡帧吧。

那到底什么时候去new?游戏场景初始化就new敌机(如以上代码)?这关会出现500个敌机那我们一次都new出来吧?浪费内存!那我们实时的去new,每到一个地方才new出来一个!浪费CPU!如果敌机线程过多造成CPU资源耗尽,每出一个敌机游戏会卡一下,试想一下这种极端情况下,游戏对象实例很多的话就是在作死。

解决方案到底是什么呢?好,原型模式Prototype!上代码!我们把上面的敌机类改造一下,让它支持原型拷贝。

public class EnemyPlane implements Cloneable{//此处实现克隆接口private int x;//敌机横坐标private int y = 0;//敌机纵坐标public EnemyPlane(int x) {//构造器this.x = x;}public int getX() {return x;}public int getY() {return y;}public void fly(){//让敌机飞y++;//每调用一次,敌机飞行时纵坐标+1}//此处开放setX,为了让克隆后的实例重新修改x坐标public void setX(int x) {this.x = x;}//为了保证飞机飞行的连贯性//这里我们关闭setY方法,不支持随意更改Y纵坐标
//    public void setY(int y) {
//        this.y = y;
//    }//重写克隆方法@Overridepublic EnemyPlane clone() throws CloneNotSupportedException {return (EnemyPlane)super.clone();}
}

注意看从第21行开始的修改,setX()方法为了保证克隆飞机的个性化,因为它们出现的位置是不同的。第34行的克隆方法重写我们调用了父类Object的克隆方法,这里JVM会进行内存操作直接拷贝原始数据流,简单粗暴,不会有其他更多的复杂操作(类加载,实例化,初始化等等),速度远远快于实例化操作。OK,我们看怎么克隆这些敌机,做一个造飞机的工厂吧。

public class EnemyPlaneFactory {//此处用懒汉模式造一个敌机原型private static EnemyPlane protoType = new EnemyPlane(200);//获取敌机克隆实例public static EnemyPlane getInstance(int x){EnemyPlane clone = protoType.clone();//复制原型机clone.setX(x);//重新设置克隆机的x坐标return clone;}
}

此处我们省去抓异常,随后的事情就非常简单了,我们只需要很简单地调用EnemyPlaneFactory.getInstance(int x)并声明x坐标位置,一架敌机很快地就做好了,并且我们保证是在敌机出现的时候再去克隆,确保不要一开局就全部克隆出来,如此一来,既保证了实时性节省了内存空间,又保证了敌机实例化的速度,游戏绝不会卡帧!至于此处代码中的懒汉原型还可以怎样优化那就要根据具体场景了,交给大家自由发挥吧,这里只说明主要问题。

最后,还要强调一点就是浅拷贝和深拷贝的问题。假如我们的敌机类里有一颗子弹bullet可以射击我们的主角,如下。

public class EnemyPlane implements Cloneable{private Bullet bullet = new Bullet();private int x;//敌机横坐标private int y = 0;//敌机纵坐标//之后代码省略……
}

我们都知道Java中的变量分为原始类型和引用类型,所谓浅拷贝只是拷贝原始类型的指,比如坐标x, y的指会被拷贝到克隆对象中,对于对象bullet也会被拷贝,但是请注意拷贝的只是地址而已,那么多个地址其实真正指向的对象还是同一个bullet。

由于我们调用父类Object的clone方法进行的是浅拷贝,所以此处的bullet并没有被克隆成功,比如我们每架敌机必须携带的子弹是不同的实例,那么我们就必须进行深拷贝,于是我们的代码就得做这样的改动。

public class EnemyPlane implements Cloneable{private Bullet bullet = new Bullet();public void setBullet(Bullet bullet) {this.bullet = bullet;}@Overrideprotected EnemyPlane clone() throws CloneNotSupportedException {EnemyPlane clonePlane = (EnemyPlane) super.clone();//先克隆出敌机,其中子弹还未进行克隆。clonePlane.setBullet(this.bullet.clone());//对子弹进行深拷贝return clonePlane;}//之后代码省略……
}

相信大家看注释就能懂了,这里就不做过多解释,当然对于Bullet类也同样实现了克隆接口,代码不用再写了吧?相信大家都学会了举一反三。至此,我们的每个敌机携带的弹药也同样被克隆完毕了,再也不必担心游戏的流畅性了。

设计模式是什么鬼(原型)相关推荐

  1. 设计模式是什么鬼3(原型)

    设计模式是什么鬼(原型) 原创: 凸凹里歐 Java知音 Java知音 微信号 Java_friends 功能介绍 专注于Java领域,每天推送全网高质量技术文章,热门开源项目,实用视频教程等.致力打 ...

  2. Java描述设计模式(05):原型模式

    一.原型模式简介 1.基础概念 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象. 2.模式结构 原型模式要求对象实现一个 ...

  3. 设计模式学习笔记——原型(Prototype)框架

    设计模式学习笔记--原型(Prototype)框架 @(设计模式)[设计模式, 原型模式, prototype] 设计模式学习笔记原型Prototype框架 基本介绍 原型案例 类图 实现代码 Pro ...

  4. 设计模式是什么鬼(模板方法)

    转自:设计模式是什么鬼(模板方法) 面向对象,是对事物属性与行为的封装,方法,指的就是行为.模板方法,显而易见是说某个方法充当了模板的作用,其充分利用了抽象类虚实结合的特性,虚部抽象预留,实部固定延续 ...

  5. 设计模式是什么鬼(状态)

    转自:设计模式是什么鬼(状态) 状态State,指某事物所处的状况或形态,比如水的三态,零下会变成固态冰,常温会是液态水,100℃会蒸发成气态的水蒸气. 在这个地球生态系统中,水的总量并不会增加,也不 ...

  6. 设计模式是什么鬼(单例)

    转自:设计模式是什么鬼(单例) 之前我们讲过面向对象以及封装.继承.多态三大特性,底子打好了那我们就把设计模式一个个拆开来看看到底都是神些什么鬼,我们先从简单的单例说起吧.单例,顾名思义,整个系统其实 ...

  7. 设计模式是什么鬼(解释器)

    原文链接:设计模式是什么鬼(解释器) 更多文章,欢迎访问:Java知音,一个专注于技术分享的网站 解释,一定是针对某种语言的拆解.释意,并按照文法翻译.转换成另一种表达形式以达到目标能够理解的目的.比 ...

  8. 设计模式学习笔记-原型模式

    一.概述 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象: 二.模式中的角色 Prototype:声明一个克隆自身的接口: ConcretePrototype:实现一个克隆自身的操作: ...

  9. [js]设计模式小结对原型的修改

    js设计模式小结 工厂模式/构造函数--减少重复- 创建对象有new- 自动创建obj,this赋值- 无return原型链模式 - 进一步去重类是函数数据类型,每个函数都有prototypecons ...

最新文章

  1. 独家 | 如何解决深度学习泛化理论
  2. 《FPGA全程进阶---实战演练》第一章之如何学习FPGA
  3. 平安金管家显示连接服务器失败,平安金管家平安run上传步数失败请更换原设备手机详细解决教程...
  4. 第5课 开心的金明《聪明人的游戏:信息学探秘.提高篇》
  5. spring事务的传播性的理解
  6. java spark on hive_hive-on-spark 安装 以及 scala 实例
  7. 腾讯第一季度总收入1353亿元 净利润478亿元
  8. Java开发框架——Struts框架
  9. 正确的Kado ED「永遠のこたえ」
  10. 移动机器人路径规划算法研究综述(一)
  11. 苹果产品信息查询_除了让你买买买,苹果官网还隐藏着这些超实用网页工具
  12. android ppt 转图片显示不全,ppt转pdf图片显示不全怎么办
  13. FortiGate常用命令
  14. 千粉缔造760w播放!B站“新人”UP主在B站怎么加速上位?
  15. 【模拟电路】431基准电压源
  16. 1012: 8除不尽的数
  17. js数组查找最接近_js 2种方法从数组里面找到最接近某个数值的值(小于该指定值,并且大于其他值)...
  18. js一数组按照另一数组进行排序
  19. 联想y700台式计算机图片,细论联想Y700台式机的自我修养
  20. 收发文系统 php,收发文表_表单设计_OA系统_泛普软件

热门文章

  1. 微信iOS版上线新功能:输入文字又变得容易一点了
  2. 易到司机无法提现:客服电话变空号,要钱无路
  3. 狂奔的瑞幸咖啡讲了一个好故事 但还缺失一种 “感觉”
  4. SpaceX载人龙飞船Crew Dragon成功完成首飞返回地球!
  5. 简单的Postman,硬是玩出花!我能咋办
  6. java smtp pop3_POP3/SMTP指令
  7. c++基于asio的组播:windows linux通信
  8. webservice无法理解soap头action_数学是对理解的追求,而不仅仅是追求计算
  9. 从H264/H265码流中获取宽、高及帧率
  10. tcpdump工具编译记录