设计模式之原型模式
Posted ProChick
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之原型模式相关的知识,希望对你有一定的参考价值。
1.简要概述
- 原型模式很类似与现实世界中的克隆技术,就是以某个对象为原型,然后复制出新的对象,该对象具备原型对象的所有特点。
- 原型模式用于创建重复的对象,同时又能保证性能,它提供了一种创建对象的最佳方式。
- 原型模式创建对象的过程,就是使用原型实例指定要创建对象的类型,然后通过复制这个原型来创建新对象。
- 原型模式的克隆方式与new方式有很大不同,采用new方式创建的对象属性值采用的是默认值,而克隆出的对象的属性值完全和原型对象相同,并且克隆出的对象发生改变不会影响原型对象。
- 原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
2.模式结构
👉通常由一个原型接口(
负责定义创建所有原型实例的接口
),多个具体的原型实现类(负责实现对相应对象实例进行克隆的内部逻辑
),一个客户类(负责调用原型接口来创建指定的原型实例
)共同组成。
3.实现代码
举例 💡 :假设我们自定义一个原型接口,然后让多个具体的原型实体去实现这个接口,完成该原型实体的克隆操作。
原型接口
public interface MyPrototype {
MyPrototype clone();
}
实体类1
public class Student implements MyPrototype {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public MyPrototype clone() {
return new Student(name);
}
}
实体类2
public class Teacher implements MyPrototype {
private String name;
public Teacher(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public MyPrototype clone() {
return new Teacher(name);
}
}
客户类
// 测试客户端
public class PrototypeClient{
public static void main(String[] args) {
// 使用原型模式创建学生实体
Student stu = new Student("我是学生");
Student stu1 = (Student) stu.clone();
Student stu2 = (Student) stu.clone();
System.out.println(stu1.getName()); // 我是学生
System.out.println(stu2.getName()); // 我是学生
System.out.println(stu1 == stu2); // false
// 使用原型模式创建老师实体
Teacher tea = new Student("我是老师");
Teacher tea1 = (Teacher) tea.clone();
Teacher tea2 = (Teacher) tea.clone();
System.out.println(tea1.getName()); // 我是老师
System.out.println(tea2.getName()); // 我是老师
System.out.println(tea1 == tea2); // false
}
}
4.优点好处
- 在创建对象时,执行效率高,避免了重新执行构造的整个过程。
- 不用重新初始化对象,而是动态的获得对象运行时的状态。
- 如果原始对象内部发生变化,那么克隆对象也会跟着发生变化,不需要修改代码。
5.缺点弊端
如果我们系统中的实体类比较多时,我们则需要为每一个类都配备一个克隆方法,过程相对繁琐。
6.应用场景
- 当通过new方式创建一个对象需要非常繁琐的过程的时候使用。
- 当在短时间内需要创建大量的重复对象的时候使用。
7.应用示例
JDK源码中的Cloneable接口
public class Student implements Cloneable{
...
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
从上方代码可以看出,我们的Student类实现了Cloneable这个原型接口类,然后重写了clone()方法,实现了当前对象的克隆操作。
Spring框架中Bean对象的创建
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Object stu1 = applicationContext.getBean("Student");
Object stu2 = applicationContext.getBean("Student");
System.out.println(stu1.toString());
System.out.println(stu2.toString());
System.out.println(stu1 == stu2); // false
当我们点击getBean()方法的实现,如下:
我们发现这里面有一个判断是否通过原型方式创建Bean实例的过程,其实这里面就用到了原型模式。
8.深克隆和浅克隆
-
浅克隆:复制对象所有的变量都含有与原来对象相同的值,而所有的对象引用都仍然指向原来的对象引用。Cloneable接口中的clone方法默认就是浅克隆。
-
深克隆:在浅克隆的基础上,深克隆把对象引用也创建了一份,而不是指向原来对象的引用。可以通过重写Cloneable接口中的clone方法,或者采用对象序列化的手段实现深克隆。
待克隆的实体类
public class Student{ private String name; private Teacher teacher; public Student(String name, Teacher teacher){ this.name = name; this.teacher = teacher; } // get和set方法 ... }
重写clone()方法进行实现
public class Student implements Cloneable{ @Override protected Object clone() { Object obj = null; try{ obj = super.clone(); Student stu = (Student) obj; stu.teacher = (Teacher) stu.teacher.clone(); return stu; } catch(Exception e){ //... } } }
采用对象序列化手段进行实现
public class Student implements Serializable{ public Object clone() { Object obj = null; try{ obj = super.clone(); // 序列化 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(obj); // 反序列化 byte[] bytes = bos.toByteArray(); ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectIutputStream ois = new ObjectIutputStream(bis); Student stu = (Student) ois.readObject(); return stu; } catch(Exception e){ //... } } }
以上是关于设计模式之原型模式的主要内容,如果未能解决你的问题,请参考以下文章