1.原型(Prototype)

本文总结参考[https://mp.weixin.qq.com/s/ojpzNHBHSh-71w9ynqQDpw],如有问题,请联系删除!
原型(Prototype):工业生产中通常是指在量产之前研发出的概念实现,如果可行性满足即可参照原型进行量产。

原型模式,实际上是从原型实例复制克隆出新实例,而绝不是从类去实例化.

栗子-敌机类

 1 public class EnemyPlane {
 2    private int x;//敌机横坐标
 3    private int y = 0;//敌机纵坐标
 4
 5    public EnemyPlane(int x) {//构造器
 6        this.x = x;
 7    }
 8
 9    public int getX() {
10        return x;
11    }
12
13    public int getY() {
14        return y;
15    }
16
17    public void fly(){//让敌机飞
18        y++;//每调用一次,敌机飞行时纵坐标+1
19    }
20}

实例化50架敌机

 1public class Client {
 2    public static void main(String[] args) {
 3        List<EnemyPlane> enemyPlanes = new ArrayList<EnemyPlane>();
 4
 5        for (int i = 0; i < 50; i++) {
 6            //此处随机位置产生敌机
 7            EnemyPlane ep = new EnemyPlane(new Random().nextInt(200));
 8            enemyPlanes.add(ep);
 9        }
10
11    }
12}

代码第7行,每个迭代都实例化new出一个对象存在性能问题.构造方法会被调用50次,cpu被极大浪费了,内存被极大浪费了,尤其对于游戏来说性能瓶颈绝对是大忌,这会造成用户体验问题,玩游戏会卡帧。

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

解决方案:原型模式Prototype,把上面的敌机类改造一下,让它支持原型拷贝。

 1public class EnemyPlane implements Cloneable{//此处实现克隆接口
 2    private int x;//敌机横坐标
 3    private int y = 0;//敌机纵坐标
 4
 5    public EnemyPlane(int x) {//构造器
 6        this.x = x;
 7    }
 8
 9    public int getX() {
10        return x;
11    }
12
13    public int getY() {
14        return y;
15    }
16
17    public void fly(){//让敌机飞
18        y++;//每调用一次,敌机飞行时纵坐标+1
19    }
20
21    //此处开放setX,为了让克隆后的实例重新修改x坐标
22    public void setX(int x) {
23        this.x = x;
24    }
25
26    //为了保证飞机飞行的连贯性
27    //这里我们关闭setY方法,不支持随意更改Y纵坐标
28//    public void setY(int y) {
29//        this.y = y;
30//    }
31
32    //重写克隆方法
33    @Override
34    public EnemyPlane clone() throws CloneNotSupportedException {
35        return (EnemyPlane)super.clone();
36    }
37}

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

 1public class EnemyPlaneFactory {
 2    //此处用痴汉模式造一个敌机原型
 3    private static EnemyPlane protoType = new EnemyPlane(200);
 4
 5    //获取敌机克隆实例
 6    public static EnemyPlane getInstance(int x){
 7        EnemyPlane clone = protoType.clone();//复制原型机
 8        clone.setX(x);//重新设置克隆机的x坐标
 9        return clone;
10    }
11}

调用EnemyPlaneFactory.getInstance(int x)并声明x坐标位置,一架敌机很快地就做好了,并且我们保证是在敌机出现的时候再去克隆,确保不要一开局就全部克隆出来,如此一来,既保证了实时性节省了内存空间,又保证了敌机实例化的速度,游戏绝不会卡帧!

浅拷贝和深拷贝
浅拷贝是拷贝原始类型的指,比如坐标x, y的指会被拷贝到克隆对象中,对于对象bullet也会被拷贝,但是请注意拷贝的只是地址而已。

原型模式的优缺点

优点
Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

缺点
需要为每一个类都配置一个 clone 方法
clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。

posted @ 2021-03-30 20:07  Ishton  阅读(621)  评论(0)    收藏  举报