美文网首页
23种设计模式之原型模式

23种设计模式之原型模式

作者: 阿跳爱学习 | 来源:发表于2018-12-22 10:10 被阅读0次

    优点:主要用于对象复制,可克隆出来再做赋值修改以达到对象满足,减少new对象的性能损耗,克隆类似于new,但跟new不同,new是所有属性都是默认值,而克隆是带原型对象中的值。
    缺点:逃避构造函数的约束。

    分三部分:
    1.浅复制
    2.深复制
    3.序列化反序列化实现深复制

    以保时捷为例子,创建一台车,然后复制一台车,想要做到复制,只需在类中做两件事:
    1.需要实现Cloneable 接口
    2.继承Object的clone方法

    浅复制
    import java.util.Date;
    
    /**
     * 这是一个保时捷实体类
     * porscheModel 保时捷型号
     * interior 内饰
     * wheelHub 轮毂规格
     * date 生产时间
     */
    
    public class Porsche implements Cloneable {
    
        private String porscheModel;
        private String interior;
        private int wheelHub;
        private Date date;
    
        public Porsche(){
    
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        public String getPorscheModel() {
            return porscheModel;
        }
    
        public void setPorscheModel(String porscheModel) {
            this.porscheModel = porscheModel;
        }
    
        public String getInterior() {
            return interior;
        }
    
        public void setInterior(String interior) {
            this.interior = interior;
        }
    
        public int getWheelHub() {
            return wheelHub;
        }
    
        public void setWheelHub(int wheelHub) {
            this.wheelHub = wheelHub;
        }
    
        public Date getDate() {
            return date;
        }
    
        public void setDate(Date date) {
            this.date = date;
        }
    }
    

    测试:

    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.FragmentActivity;
    import android.util.Log;
    
    import com.hdc.test.prototype.Porsche;
    
    import java.util.Date;
    
    /**
     * 这是调用者
     */
    
    public class MainActivity extends FragmentActivity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Date date = new Date(351213211);
            Porsche porsche = new Porsche();
            porsche.setPorscheModel("保时捷911");
            porsche.setInterior("石榴红真皮内饰");
            porsche.setWheelHub(20);
            porsche.setDate(date);
    
            try {
                //浅复制
                Porsche porsche2 = (Porsche) porsche.clone();
                //打印
                Log.d("TAG", "原型对象:" + porsche + "\n克隆对象:" + porsche2);
                Log.d("TAG", "原型对象date的值:" + porsche.getDate() + "\n克隆对象date的值:" + porsche2.getDate());
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    }
    

    结果:


    image.png

    克隆出了一个全新对象,值也都是一样的,引用地址也是一样的,但是浅克隆会有一个问题,就是当你把Date对象修改之后,克隆对象的值也会跟着改变。
    测试:

    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.FragmentActivity;
    import android.util.Log;
    
    import com.hdc.test.prototype.Porsche;
    
    import java.util.Date;
    
    /**
     * 这是调用者
     */
    
    public class MainActivity extends FragmentActivity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Date date = new Date(351213211);
            Porsche porsche = new Porsche();
            porsche.setPorscheModel("保时捷911");
            porsche.setInterior("石榴红真皮内饰");
            porsche.setWheelHub(20);
            porsche.setDate(date);
            Log.d("TAG", "修改前原型对象date的值:" + porsche.getDate());
    
            try {
                //浅复制
                Porsche porsche2 = (Porsche) porsche.clone();
                //克隆完成后修改date的值
                date.setTime(325623262);
    
                //打印
                Log.d("TAG", "原型对象date的值:" + porsche.getDate() + "\n克隆对象date的值:" + porsche2.getDate());
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    }
    

    结果:


    image.png

    克隆对象porsche2 时间也随之改变了,我在date修改前已经复制出来了,为什么还是会改变?因为porsche和porsche2 引用的是同一个对象,他们获取值的引用地址是一样的,当引用地址的值被改变之后,他们也随之改变,因此要避免这种情况需要用到深复制。

    深复制

    很简单,Porsche 实体类中的clone()方法做以下重写,把属性也进行克隆就好

     @Override
        public Object clone() throws CloneNotSupportedException {
            Object obj = super.clone();
            Porsche porsche = (Porsche) obj;
            porsche.date = (Date) this.date.clone();
            return obj;
        }
    
    结果: image.png

    这样就能保证,当引用地址值发生改变时,克隆对象中的值不会发生改变。

    序列化与反序列化实现深复制

    序列化之前实体类需要实现Serializable,clone方法返回父类的clone方法就行了,不需要重写。

    import java.io.Serializable;
    import java.util.Date;
    
    /**
     * 浅复制
     * 这是一个保时捷实体类
     * porscheModel 保时捷型号
     * interior 内饰
     * wheelHub 轮毂规格
     * date 生产时间
     */
    
    public class Porsche implements Cloneable, Serializable {
    
        private String porscheModel;
        private String interior;
        private int wheelHub;
        private Date date;
    
        public Porsche() {
    
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    
        public String getPorscheModel() {
            return porscheModel;
        }
    
        public void setPorscheModel(String porscheModel) {
            this.porscheModel = porscheModel;
        }
    
        public String getInterior() {
            return interior;
        }
    
        public void setInterior(String interior) {
            this.interior = interior;
        }
    
        public int getWheelHub() {
            return wheelHub;
        }
    
        public void setWheelHub(int wheelHub) {
            this.wheelHub = wheelHub;
        }
    
        public Date getDate() {
            return date;
        }
    
        public void setDate(Date date) {
            this.date = date;
        }
    }
    

    测试:

    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.FragmentActivity;
    import android.util.Log;
    
    import com.hdc.test.prototype.Porsche;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.util.Date;
    
    /**
     * 这是调用者
     */
    
    public class MainActivity extends FragmentActivity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Date date = new Date(351213211);
            Porsche porsche = new Porsche();
            porsche.setPorscheModel("保时捷911");
            porsche.setInterior("石榴红真皮内饰");
            porsche.setWheelHub(20);
            porsche.setDate(date);
            Log.d("TAG", "修改前原型对象date的值:" + porsche.getDate());
    
            try {
                //序列化和反序列化实现深复制
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(bos);
                oos.writeObject(porsche);
                byte[] bytes = bos.toByteArray();
    
                ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
                ObjectInputStream ois = new ObjectInputStream(bis);
                Porsche porsche2 = (Porsche) ois.readObject();
    
                //克隆完成后修改date的值
                date.setTime(325623262);
    
                //打印
                Log.d("TAG", "原型对象date的值:" + porsche.getDate() + "\n克隆对象date的值:" + porsche2.getDate());
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    

    结果:


    image.png

    引用地址的值发生改变,克隆对象数据并未改变,这样一样可以实现深复制。

    最后以new对象以及克隆对象的耗时测试作为总结:
    模拟对象耗时操作:

    /**
     * 保时捷911实体类
     * 模拟对象耗时操作,假设创建一个对象需要5秒
     */
    
    public class Porsche911 implements Cloneable {
    
        public Porsche911() {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.FragmentActivity;
    import android.util.Log;
    
    import com.hdc.test.prototype.Porsche911;
    
    /**
     * 这是调用者
     */
    
    public class MainActivity extends FragmentActivity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //都创建1000个对象
            testNew(1000);
            testClone(1000);
        }
    
        //new的方式构建对象
        private void testNew(int size) {
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < size; i++) {
                Porsche911 porsche911 = new Porsche911();
            }
            long endTime = System.currentTimeMillis();
            Log.d("TAG", "New方式创建对象耗时:" + (endTime - startTime));
        }
    
        private void testClone(int size) {
            long startTime = System.currentTimeMillis();
            Porsche911 porsche911 = new Porsche911();
            for (int i = 0; i < size; i++) {
                try {
                    Porsche911 porsche9112 = (Porsche911) porsche911.clone();
                } catch (CloneNotSupportedException e) {
                    e.printStackTrace();
                }
            }
            long endTime = System.currentTimeMillis();
            Log.d("TAG", "clone方式创建对象耗时:" + (endTime - startTime));
        }
    }
    

    结果:


    image.png

    如果是很耗时的对象的话,效率差的不是一星半点。
    已完成测试!有不对的地方欢迎指出,感恩。

    相关文章

      网友评论

          本文标题:23种设计模式之原型模式

          本文链接:https://www.haomeiwen.com/subject/tngmkqtx.html