设计模式(九):原型模式

概述

原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。调用者不需要知道任何创建细节,不调用构造函数。

代码模拟

场景是需要获取同一个姓名的20个学生实例。

创建学生,根据姓名获取学生的时候需要去数据库查询获取学生的分数,耗时100ms

public class Student {

    private String name;

    private int score;

    //根据姓名获取学生的时候需要去数据库查询获取学生的分数,耗时100ms
    public Student(String name) {
        this.name = name;
        try {
            System.out.println("正在获取学生对应的得分");
            Thread.sleep(100);
            System.out.println("学生对应的得分是:" + 100);
            this.score = 100;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public Student() {
    }


    public String getName() {
        return name;
    }

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

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

}

定义接口,可以通过原型的方式获取Student对象

public interface Prototype {
    Student cloneStudent();
}

定义可利用原型模式获取学生对象的实现类

public class ClonableStudent extends Student implements Prototype{

    public ClonableStudent(String name) {
        super(name);
    }

    public ClonableStudent() {
    }

    @Override
    public Student cloneStudent() {
        //利用无参构造获取空对象,通过属性拷贝的方式初始化新对象
        Student stu = new Student();
        stu.setName(this.getName());
        stu.setScore(this.getScore());
        return stu;
    }
}

测试类

public class ProtoTypeTest {

    public static void main(String[] args) {
        String name = "zhangsan";
        Student stu = new Student(name);
        long start = System.currentTimeMillis();
        for(int i=0;i<20;i++){
            Student stu2 = new Student(name);
        }
        long end = System.currentTimeMillis();
        System.out.println("创建20个对象耗时:"+(end-start));
        //控制台输出:创建20个对象耗时:2184

        ClonableStudent clonableStudent = new ClonableStudent(name);
        long start2 = System.currentTimeMillis();
        for(int i=0;i<20;i++){
            Student stu2 = clonableStudent.cloneStudent();
            System.out.println("创建完第"+i+"个对象");
        }
        long end2 = System.currentTimeMillis();
        System.out.println("创建20个对象耗时:"+(end2-start2));
         //控制台输出:创建20个对象耗时:2184
    }
}

总结

原型模式的目的是减少频繁创建对象时候不必要的资源消耗(所谓不必要是指同一个姓名的学生的成绩是相同的,不需要重复去查询数据库,进行这些耗时耗资源的操作)。

浅克隆

创建hobby类,在student类增加hobby属性

public class Hobby {

    private String show;

    public Hobby(String show) {
        this.show = show;
    }

    public String getShow() {
        return show;
    }

    public void setShow(String show) {
        this.show = show;
    }
}
public class Student {

    private String name;

    private int score;

    private Hobby hobby ;
    ...

    public Hobby getHobby() {
        return hobby;
    }

    public void setHobby(Hobby hobby) {
        this.hobby = hobby;
    }
}
public class ClonableStudent extends Student implements Prototype{

    public ClonableStudent(String name) {
        super(name);
    }

    public ClonableStudent() {
    }

    @Override
    public Student cloneStudent() {
        Student stu = new Student();
        stu.setName(this.getName());
        stu.setScore(this.getScore());
        stu.setHobby(this.getHobby());
        return stu;
    }
}

测试类

public class SimpleCloneTest {
    public static void main(String[] args) {

        ClonableStudent student = new ClonableStudent();
        student.setName("www");
        student.setScore(100);
        student.setHobby(new Hobby("sing"));

        Student student1 = student.cloneStudent();
        System.out.println("源对象修改前得分:"+student1.getScore());//100
        System.out.println("源对象修改前姓名:"+student1.getName());//www
        System.out.println("源对象修改前兴趣:"+student1.getHobby().getShow());//sing

        student.setScore(60);
        student.setName("aaa");
        student.getHobby().setShow("ball");
        System.out.println("源对象修改后得分:"+student1.getScore());//100
        System.out.println("源对象修改后姓名:"+student1.getName());//www
        System.out.println("源对象修改后兴趣:"+student1.getHobby().getShow());//ball
    }
}

源对象的引用类型对象改变时,目标对象对应的属性会被修改,就像兴趣从唱歌变为了打球,但是非引用类型的属性改变时不会引起目标类的属性变化。原因是引用类型复制的是引用。

深克隆

public class DeepTest {

    public static void main(String[] args) {

        Student student = new Student();
        student.setName("www");
        student.setScore(100);
        student.setHobby(new Hobby("sing"));

        Student clonedStudent = deepcloneObj(student);
        System.out.println("源对象修改前得分:"+clonedStudent.getScore());//100
        System.out.println("源对象修改前姓名:"+clonedStudent.getName());//www
        System.out.println("源对象修改前兴趣:"+clonedStudent.getHobby().getShow());//sing

        student.setScore(60);
        student.setName("aaa");
        student.getHobby().setShow("ball");
        System.out.println("源对象修改后得分:"+clonedStudent.getScore());//100
        System.out.println("源对象修改后姓名:"+clonedStudent.getName());//www
        System.out.println("源对象修改后兴趣:"+clonedStudent.getHobby().getShow());//sing
    }


    /**
     * 对象深拷贝,新的对象的修改不会影响原始对象的值
     */
    public static <T>T deepcloneObj(T obj) {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream() ;
        ObjectInputStream objIn;
        try
        {
            ObjectOutputStream objOut =new ObjectOutputStream(byteOut);
            objOut.writeObject(obj);
            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            objIn = new ObjectInputStream(byteIn);
            return (T) objIn.readObject();
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
        return null ;
    }
}

深克隆的特点是源目标的任何属性变化不会影响克隆后的对象。

值传递与引用传递

值传递

java的基本类型和String都是值传递。意思是在把一个参数传递给方法执行的时候传了值,本身新开辟了一个空间,值和传入的一样。所以在执行完方法后原来的值不变,因为你方法里面相当于在操作一个和你值相同的另一个对象,原来的值当然不变。

引用传递

引用传递意思是传递参数的时候传递的是对象的地址,方法执行前后操作的是根据地址指向的同一个对象

这么做的原因我猜想是对象的大小不固定,值传递浪费内存太严重。但是值传递的都是基本类型或者是String,大小相对固定而且较小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值