java 设计模式之原型模式(三)

每一个优秀的人,都有一段沉默的时光。那一段时光,是付出了很多努力,忍受孤独和寂寞,不抱怨不诉苦,日后说起时,连自己都能被感动日子。

设计模式学习,近期我会把23中设计模式都写成博客,敬请期待~

什么是原型模式?

  • 原型模式是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
  • 原型设计模式是一种创建型设计模式,运行一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。
  • 工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,既 对象.clone();

百度百科

什么是克隆?

什么是克隆呢?可能大家都听说过克隆羊多利吧


就是一个已经存在的东西,完完全玩的复制一份,就称之为克隆,说的通俗一点就是拷贝粘贴~

原型设计模式思路

咋们也模仿羊来克隆出来一只多利(克隆羊),

先用普通的最简单的做法来克隆

然后在给大家介绍使用原型模式来克隆

普通方法克隆

创建一直普通的’羊’,用来克隆:

public class Sheep implements Cloneable {
    
    
    String name;//羊的名字
    int age;//样的年龄
    String color;//羊的颜色

    public Sheep(String name, int age, String color) {
    
    
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }
}

这只羊非常简单,只有名字,年龄和颜色

来看看是如何克隆的~

Sheep sp1 = new Sheep("tom", 3, "red");
Sheep sp2 = new Sheep("tom", 3, "red");

 Log.i("原型模式普通方法:",sp1.toString()+"\t hashCode:"+sp1.hashCode());
 
Log.i("原型模式普通方法:",sp2.toString()+"\t hashCode:"+sp2.hashCode());

这里非常好理解,就是new了2个羊达到’克隆’的目的

效果图(1.1):


可以看出hashCode是不一样的,说明2个内存指向不一样,那么就来验证一下.

验证方式非常简单,通过修改名字来判断会不会冲突

验证代码:

Sheep sp1 = new Sheep("tom", 3, "red");
Sheep sp2 = new Sheep("tom", 3, "red");

Log.i("原型模式普通方法:",sp1.toString()+"\t hashCode:"+sp1.hashCode());
Log.i("原型模式普通方法:",sp2.toString()+"\t hashCode:"+sp2.hashCode());

sp2.setName("jack");//修改'克隆'羊的名字为jack

Log.i("原型模式普通方法:",sp1.toString()+"\t hashCode:"+sp1.hashCode());
Log.i("原型模式普通方法:",sp2.toString()+"\t hashCode:"+sp2.hashCode());

修改’克隆’羊的名字为jack

效果图(1.2):


通过这张图可以看出:即使修改’克隆’羊也不会影响被克隆羊的参数(这里指名字).

用代码来解释就是:内存地址不一样,内存指向也不一样.这是2个完全没关系的东西

传统方式的优缺点

  • 比较好理解,简单易操作
  • 在创建新的对象时,总是需要重新获取原始对象的属性,如果创建的对象过多,效率不高。
  • 总是需要重新初始化对象,而不是动态的获取对象运行时的状态。

浅克隆

对于基本数据类型是成员变量,浅拷贝会直接进行值拷贝,也就是将该属性值复制一份给新的对象。

原型模式使用:

  • 实现Cloneable接口
  • 实现clone()方法

浅拷贝代码实现:

public class Sheep implements Cloneable {
    
    
    String name;//羊的名字
    int age;//样的年龄
    String color;//羊的颜色

    public Sheep(String name, int age, String color) {
    
    
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public Sheep(String name, int age, String color) {
    
    
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }

    @NonNull
    @Override
    public Object clone() {
    
    
        try {
    
    
            //引用对象拷贝 将对象的方法拷贝给当前的值
            Sheep sheep = (Sheep) super.clone();
            return sheep;
        } catch (Exception e) {
    
    
            Log.i("原型模式:", e.getMessage());
            return null;
        }
    }
}

实现代码:

 Sheep sheep1 = new Sheep("tom", 3, "red",lazinessSheep);

Sheep sheep2 = (Sheep) sheep1.clone();//'克隆羊'

Log.i("原型模式:", "============  克隆之前  ===============");
Log.i("原型模式:", "sheep1=>" + sheep1.toString() + "\t hashCode=>" + sheep1.hashCode());
Log.i("原型模式:", "sheep2=>" + sheep2.toString() + "\t hashCode=>" + sheep2.hashCode());

Log.i("原型模式:", "===========================");

sheep1.setName("jack");

Log.i("原型模式:", "============  克隆之后  ===============");
Log.i("原型模式:", "sheep1=>" + sheep1.toString() + "\t hashCode=>" + sheep1.hashCode());
Log.i("原型模式:", "sheep2=>" + sheep2.toString() + "\t hashCode=>" + sheep2.hashCode());

分析:

  • sheep1 是本身的羊
  • sheep2 是通过sheep1 .clone()克隆出来的羊
  • 先输出结果,然后改变sheep1本身羊的name,来看看会不会s影响heep2( 克隆羊)

效果图(1.3):


可以看出这种克隆方式对于基本数据类型能够完成很好的克隆,

这就是浅克隆

如果说我的羊现在有一只朋友’懒洋洋’来看看有如何不同:

我的朋友类:

public class LazinessSheep{
    
    
    String name = "懒洋洋";
    int age = 2;

    public LazinessSheep() {
    
    
    }


    public void setName(String name) {
    
    
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "LazinessSheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

克隆羊类:

public class Sheep implements Cloneable {
    
    
    String name;//羊的名字
    int age;//样的年龄
    String color;//羊的颜色
    public LazinessSheep lazinessSheep;//羊的朋友(懒洋洋)

    public Sheep(String name, int age, String color, LazinessSheep lazinessSheep) {
    
    
        this.name = name;
        this.age = age;
        this.color = color;
        this.lazinessSheep = lazinessSheep;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                ", lazinessSheep=" + lazinessSheep +
                '}';
    }
    @NonNull
    @Override
    public Object clone() {
    
    
        try {
    
    
            //引用对象拷贝 将对象的方法拷贝给当前的值
            Sheep sheep = (Sheep) super.clone();
            return sheep;
        } catch (Exception e) {
    
    
            Log.i("原型模式:", e.getMessage());
            return null;
        }
    }
}

实现代码:

LazinessSheep lazinessSheep = new LazinessSheep();

Sheep sheep1 = new Sheep("tom", 3, "red",lazinessSheep);

 //'克隆羊'
Sheep sheep2 = (Sheep) sheep1.clone();
Log.i("原型模式:", "============  克隆之前  ===============");
Log.i("原型模式:", "sheep1=>" + sheep1.toString() + "\t hashCode=>" + sheep1.hashCode());
Log.i("原型模式:", "sheep2=>" + sheep2.toString() + "\t hashCode=>" + sheep2.hashCode());

Log.i("原型模式:", "===========================");

sheep1.lazinessSheep.setName("灰太狼");

Log.i("原型模式:", "============  克隆之后  ===============");
Log.i("原型模式:", "sheep1=>" + sheep1.toString() + "\t hashCode=>" + sheep1.hashCode());
Log.i("原型模式:", "sheep2=>" + sheep2.toString() + "\t hashCode=>" + sheep2.hashCode());

分析:

  • lazinessSheep是我的朋友
  • sheep1是本身的羊
  • sheep2是被克隆的羊
  • 先输出第一次的结果,然后改变我朋友(lazinessSheep)的名字为灰太狼

来看看有什么不同:

效果图(1.4):


通过效果图(1.4)可以看出我们只改变了

sheep1本身的羊朋友的值(名字),但是sheep2克隆羊朋友的值(名字)也改变了

现在的问题如下:


可以看出,浅拷贝无法复制引用类型,因为他没有复制引用类型,只是吧现在的状态指向了内存地址,不管你复制10个还是20个克隆羊,引用类型还是指向的原本的内存地址

这就是浅克隆为什么不能克隆引用类型,只能克隆基本数据类型了

深克隆

所谓深克隆,就是解决浅克隆不能复制引用数据类型的问题,达到克隆的每一个个羊,都是单独的,和原本并没有区别.

深克隆代码:

public class LazinessSheep implements Cloneable{
    
    
    String name = "懒洋洋";
    int age = 2;

    public LazinessSheep() {
    
    
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
    @Override
    public String toString() {
    
    
        return "LazinessSheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @NonNull
    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }
}

将需要克隆的有引用类型也实现Cloneable接口实现clone()方法

public class Sheep implements Cloneable {
    
    
    String name;//羊的名字
    int age;//样的年龄
    String color;//羊的颜色
    public LazinessSheep lazinessSheep;//羊的朋友(懒洋洋)

    public Sheep(String name, int age, String color, LazinessSheep lazinessSheep) {
    
    
        this.name = name;
        this.age = age;
        this.color = color;
        this.lazinessSheep = lazinessSheep;
    }

    public Sheep(String name, int age, String color) {
    
    
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
    
    @Override
    public String toString() {
    
    
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                ", lazinessSheep=" + lazinessSheep +
                '}';
    }

    @NonNull
    @Override
    public Object clone() {
    
    
        try {
    
    
            //引用对象拷贝 将对象的方法拷贝给当前的值
            Sheep sheep = (Sheep) super.clone();
            lazinessSheep = (LazinessSheep) sheep.lazinessSheep.clone();
            return sheep;
        } catch (Exception e) {
    
    
            Log.i("原型模式:", e.getMessage());
            return null;
        }
    }
}

修改羊本身的类:

重点方法:

 @NonNull
    @Override
    public Object clone() {
    
    
        try {
    
    
            //引用对象拷贝 将对象的方法拷贝给当前的值
            Sheep sheep = (Sheep) super.clone();
            lazinessSheep = (LazinessSheep) sheep.lazinessSheep.clone();
            return sheep;
        } catch (Exception e) {
    
    
            Log.i("原型模式:", e.getMessage());
            return null;
        }
    }

因为这里的引用类型也是由基本数据类型组成的,

所以在这里通过

lazinessSheep = (LazinessSheep) sheep.lazinessSheep.clone();

把LazinessSheep的clone();赋值给当前类的lazinessSheep即可

实现代码:
还是上边一样的代码:

///   原型模式之深克隆   \\\\\\\\\\\\\\\\\\\\
LazinessSheep lazinessSheep = new LazinessSheep();

Sheep sheep1 = new Sheep("tom", 3, "red",lazinessSheep);

//'克隆羊'
Sheep sheep2 = (Sheep) sheep1.clone();
Log.i("原型模式:", "============  克隆之前  ===============");
Log.i("原型模式:", "sheep1=>" + sheep1.toString() + "\t hashCode=>" + sheep1.hashCode());
Log.i("原型模式:", "sheep2=>" + sheep2.toString() + "\t hashCode=>" + sheep2.hashCode());

Log.i("原型模式:", "===========================");

sheep1.lazinessSheep.setName("灰太狼");

Log.i("原型模式:", "============  克隆之后  ===============");
Log.i("原型模式:", "sheep1=>" + sheep1.toString() + "\t hashCode=>" + sheep1.hashCode());
Log.i("原型模式:", "sheep2=>" + sheep2.toString() + "\t hashCode=>" + sheep2.hashCode());

效果图(1.5):


可以看到,改变sheep1的引用数据类型lazinessSheep为灰太狼之后并没有影响克隆之后的值,这样就达到了深克隆的效果

总结

  • 浅克隆:只能克隆基本数据类型,因为克隆引用数据类型他不会创建新的内存地址,而是吧当前克隆的指向被克隆的地址
  • 深克隆:所有数据类型都可以克隆,如果原始对象发生变化,其他克隆对象也会发生相应的变化,无需修改代码。
  • 创建新的对象比较复杂时,可以使用原型模式简化对象的创建过程,同时也能提高效率。
  • 不用重新初始化对象,而是动态地获取对象运行的状态。

完整代码

最近文章:

java 设计模式之单例模式(一)

java设计模式之工厂模式(二)

java设计模式之建造者模式(四)

java 设计模式之适配器模式(五)

去设计模式/设计原则目录页

原创不易,您的点赞就是对我最大的支持,点个赞支持一下哦~

猜你喜欢

转载自blog.csdn.net/weixin_44819566/article/details/112345042
今日推荐