概述
已经实例化了一个对象。而您的对象现在处于您希望从中复制自身的状态。换句话说,您想要克隆对象。如果您只是将对象引用分配给使用类似类型声明的另一个变量,因为这些是对象引用而不是实际数据。因此,您需要做的是实例化一个新对象并复制所有属性。
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
应用实例
1、细胞分裂。
2、JAVA 中的 Object clone() 方法。
优点
- 性能提高。
- 逃避构造函数的约束。
缺点
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。
- 必须实现 Cloneable 接口。
使用场景
- 资源优化场景。
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景。
- 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景。
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
- 在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
实现
我们将创建一个抽象类 CL_Shape 和扩展了 CL_Shape 类的实体类。下一步是定义类 CL_Shape_Cache,该类把 CL_shape 对象存储在一个 Hashtable 中,并在请求的时候返回它们的克隆。
UML:
1. 创建一个实现了 Cloneable 接口的类。
INTERFACE if_cloneable.
METHODS clone
RETURNING VALUE(ro_instance) TYPE REF TO if_cloneable.
ENDINTERFACE.
CLASS cl_shape DEFINITION.
PUBLIC SECTION.
INTERFACES if_cloneable.
METHODS:draw.
METHODS:get_type
RETURNING VALUE(rv_type) TYPE string.
METHODS:get_id
RETURNING VALUE(rv_id) TYPE string.
METHODS:set_id
IMPORTING iv_id TYPE string.
PROTECTED SECTION.
DATA:mv_type TYPE string.
PRIVATE SECTION.
DATA:mv_id TYPE string.
ENDCLASS.
CLASS cl_shape IMPLEMENTATION.
METHOD if_cloneable~clone.
DATA(lo_shape) = NEW cl_shape( ).
lo_shape->mv_id = mv_id .
lo_shape->mv_type = mv_type.
ro_instance = lo_shape.
ENDMETHOD.
METHOD draw.
ENDMETHOD.
METHOD get_type.
rv_type = mv_type.
ENDMETHOD.
METHOD get_id.
rv_id = mv_id.
ENDMETHOD.
METHOD set_id.
mv_id = iv_id.
ENDMETHOD.
ENDCLASS.
2. 创建扩展了上面抽象类的实体类。
CLASS cl_rectangle DEFINITION INHERITING FROM cl_shape.
PUBLIC SECTION.
METHODS constructor.
METHODS draw REDEFINITION.
ENDCLASS.
CLASS cl_rectangle IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
me->mv_type = 'Rectangle'.
ENDMETHOD.
METHOD draw.
WRITE:/ 'Inside CL_Rectangle->draw() method.'.
ENDMETHOD.
ENDCLASS.
CLASS cl_square DEFINITION INHERITING FROM cl_shape.
PUBLIC SECTION.
METHODS constructor.
METHODS draw REDEFINITION.
ENDCLASS.
CLASS cl_square IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
me->mv_type = 'Square '.
ENDMETHOD.
METHOD draw.
WRITE:/ 'Inside CL_Square->draw() method.'.
ENDMETHOD.
ENDCLASS.
3. 创建一个类,从数据库获取实体类,并把它们存储在一个 Hashtable 中。
CLASS cl_shape_cache DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:get_shape
IMPORTING
iv_id TYPE string
RETURNING VALUE(ro_instance) TYPE REF TO cl_shape.
CLASS-METHODS load_cache
.
PRIVATE SECTION.
TYPES:BEGIN OF ty_hash_table,
id TYPE string,
shape TYPE REF TO cl_shape,
END OF ty_hash_table.
CLASS-DATA:mt_hash_table TYPE TABLE OF ty_hash_table .
ENDCLASS.
CLASS cl_shape_cache IMPLEMENTATION.
METHOD get_shape.
READ TABLE mt_hash_table INTO DATA(ls_hash_table) WITH KEY id = iv_id.
ro_instance ?= ls_hash_table-shape->if_cloneable~clone( ).
ENDMETHOD.
METHOD load_cache.
DATA(lo_rectangle) = NEW cl_rectangle( ).
lo_rectangle->set_id('1').
mt_hash_table = VALUE #( BASE mt_hash_table ( id = lo_rectangle->get_id( ) shape = lo_rectangle ) ).
DATA(lo_square) = NEW cl_square( ).
lo_square->set_id('2').
mt_hash_table = VALUE #( BASE mt_hash_table ( id = lo_square->get_id( ) shape = lo_square ) ).
ENDMETHOD.
ENDCLASS.
4.写个主程序执行
CLASS cl_application DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: run .
ENDCLASS.
CLASS cl_application IMPLEMENTATION.
METHOD run.
cl_shape_cache=>load_cache( ).
DATA(lo_cloned_shape1) = cl_shape_cache=>get_shape( '1' ).
WRITE:/ 'Shape : ' ,lo_cloned_shape1->get_type( ).
DATA(lo_cloned_shape2) = cl_shape_cache=>get_shape( '2' ).
WRITE:/ 'Shape : ' ,lo_cloned_shape2->get_type( ).
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
cl_application=>run( ).
5.执行程序,输出结果