`

设计模式之原型模式

阅读更多

原型模式是一种创建型的模式,原型模式的简单程度仅次于单例模式和迭代器模式,正是由于简单,使用的场景非常多。

 



 通过原型模式的通用类图可以看到,其实原型模式的核心就是一个clone方法,通过该方法实现对象的拷贝。

 

原型模式的优点:

1.原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量对象时。

2.规避构造方法的约束,因为原型模式是在内存二进制流的拷贝,所以是不会调用构造方法的

 

原型模式的使用场景

1.类的初始化需要消耗非常多的资源(数据、硬件资源等)

2.性能和安全的要求,因为通过new产生一个对象需要非常繁琐的数据准备或访问权限

 

克隆满足的条件:

 

  clone()方法将对象复制了一份并返还给调用者。所谓“复制”的含义与clone()方法是怎么实现的。一般而言,clone()方法满足以下的描述:

 

(1)对任何的对象x,都有:x.clone()!=x。换言之,克隆对象与原对象不是同一个对象。

 

(2)对任何的对象x,都有:x.clone().getClass() == x.getClass(),换言之,克隆对象与原对象的类型一样。

 

(3)如果对象x的equals()方法定义其恰当的话,那么x.clone().equals(x)应当成立的。

 

  在JAVA语言的API中,凡是提供了clone()方法的类,都满足上面的这些条件。JAVA语言的设计师在设计自己的clone()方法时,也应当遵守着三个条件。一般来说,上面的三个条件中的前两个是必需的,而第三个是可选的。

 

可能分为浅克隆和深克隆

 

先看一个例子,看看什么是浅克隆:

 

public class Something implements Cloneable {

    private List<String> list = new ArrayList<String>();

    // 重写Object类中的clone方法
    @Override
    protected Something clone() {
        Something something = null;

        try {
            something = (Something) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return something;
    }

    public void setValue(String value) {

        this.list.add(value);
    }

    public List<String> getList() {

        return this.list;
    }

    public static void main(String[] args) {
        
        //产生一个对象
        Something something=new Something();
        
        something.setValue("aaa");
        
        //克隆一个对象
        Something thing=something.clone();
        
        thing.setValue("bbb");
        
        System.out.println(something.getList());//结果:[aaa, bbb]

    }

}

 

 

从输出结果看,这并不是我们想要的拷贝,Object类提供的clone方法只是拷贝对象,对于对象内部的数组、引用对象都不拷贝,还是指向原生对象的内部元素,这种拷贝就是浅拷贝。

 

  •   浅度克隆

 

  只负责克隆按值传递的数据(比如基本数据类型、String类型),而不复制它所引用的对象,换言之,所有的对其他对象的引用都仍然指向原来的对象。

 

  •   深度克隆

 

  除了浅度克隆要克隆的值外,还负责克隆引用类型的数据。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深度克隆把要复制的对象所引用的对象都复制了一遍,而这种对被引用到的对象的复制叫做间接复制。

 

  深度克隆要深入到多少层,是一个不易确定的问题。在决定以深度克隆的方式复制一个对象的时候,必须决定对间接复制的对象时采取浅度克隆还是继续 采用深度克隆。因此,在采取深度克隆时,需要决定多深才算深。此外,在深度克隆的过程中,很可能会出现循环引用的问题,必须小心处理。

 

下面以一个场景来叙述一下原型模式的使用,相信大家在大学考试的时候都有过打小抄的情况(没有也不能说明什么吐舌头),上一面代理模式中说道小明同学找代理打游戏,但是人就不去上课,整体的睡懒觉,好了一个学期过去,今天同小强说马上要考试了,小明很惊讶的说:“不是吧,大学还有考试啊?”此处只能呵呵,那么小明如何应对考试呢,当然是自己上了这么多年学积累下来的经验了,那就是抄别人的.....

 



 

 

代码如下:

 

 

/**
 * 试卷
 * 
 */
public class Paper implements Cloneable {

    private Student student=new Student();

    @Override
    protected Paper clone() {

        Paper paper = null;

        try {
            paper = (Paper) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return paper;
    }

    // 获取学生信息
    public Student getStudent() {

        return this.student;
    }

    // 获取考生姓名
    public void setName(String name) {

        this.student.setName(name);
    }

    public int getResult() {

        return 29;
    }

}

 

 

 

/**
 * 
 * 
 */
public class Student {

    // 学生姓名
    private String name;

    // 学生学号
    private String no;

    public String getName() {
        return name;
    }

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

    public String getNo() {
        return no;
    }

    public void setNo(String no) {
        this.no = no;
    }

}

 

 

 

public class Client {

    public static void main(String[] args) {
        
        //生成一份试卷
        Paper paper=new Paper();
        //考生姓名
        paper.setName("小强");
        
        //小明复制一份小强的试卷
        Paper clonePaper=paper.clone();
        
        clonePaper.setName("小明");
        
        System.out.println(paper.getStudent().getName());
    }
}

 

这段程序的输出结果是小明,那小强呢?这就是浅拷贝,结果就是两份试卷的答题人都变成了小明。

  • 大小: 11.5 KB
  • 大小: 19 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics