【设计模式】创建型模式:原型模式

意图

原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。

问题

现在有一个对象, 并希望生成与其完全相同的一个复制品(其所有成员变量都要相同)。但有些对象可能拥有私有成员变量, 它们在对象本身以外是不可见的。
只复制外形,没有复制不可见的功能

解决方案

原型模式将克隆过程委派给被克隆的实际对象。模式为所有支持克隆的对象声明了一个通用接口, 该接口让你能够克隆对象,同时又无需将代码和对象所属类耦合。通常情况下,这样的接口中仅包含一个克隆方法。
clone函数 和 拷贝构造函数作用类似。
原型URL图

示例代码

以下是 AWTK-MVVM 使用原型模式克隆 list_view 中的子控件的部分示例代码:

<!-- books.xml -->
   <list_view x="0"  y="30" w="100%" h="-80" item_height="40">
    <scroll_view name="column" x="0"  y="0" w="100%" h="100%" v-for-items="true">
      <list_item children_layout="default(rows=1,cols=0,s=4)">
        <property name="v-data:style">
          <![CDATA[ {($index % 2) ? "odd" : "even"} ]]>
        </property>

        <label w="20" v-data:text="{index}"/>
        <label w="35%" v-data:text="{item.name}"/>
        <label w="40" v-data:text="{item.stock}"/>
        <column  w="128" children_layout="default(rows=1,cols=0,s=5,ym=5)">
          <button w="70" text="Remove" v-on:click="{remove}"/>
          <button w="50" text="Sale" v-on:click="{sale}"/>
        </column>
      </list_item>
    </scroll_view>
    <scroll_bar_m name="bar" x="right" y="0" w="6" h="100%" value="0"/>
  </list_view>
/* binding_context_awtk.c */
static widget_t* binding_context_get_widget(binding_context_t* ctx, widget_t* container) {
  darray_t* cache = &(ctx->cache_widgets);
  widget_t* widget = darray_pop(cache);
  if (widget == NULL) {
    widget_t* template_widget =
        WIDGET(widget_get_prop_pointer(container, WIDGET_PROP_TEMPLATE_WIDGET));
    /* 克隆 */
    widget = widget_clone(template_widget, NULL);
  }

  return widget;
}

static ret_t binding_context_prepare_children(binding_context_t* ctx, widget_t* widget) {
  uint32_t i = 0;
  view_model_t* view_model = ctx->view_model;
  uint32_t items = object_get_prop_int(OBJECT(view_model), VIEW_MODEL_PROP_ITEMS, 0);
  widget_t* template_widget = WIDGET(widget_get_prop_pointer(widget, WIDGET_PROP_TEMPLATE_WIDGET));

  if (template_widget == NULL) {
    /* 将第一个子控件保存为原型 */
    template_widget = widget_get_child(widget, 0);
    widget_set_prop_pointer(widget, WIDGET_PROP_TEMPLATE_WIDGET, template_widget);
    widget_on(widget, EVT_DESTROY, binding_context_on_container_destroy, widget);

    widget_remove_child(widget, template_widget);
  }

  widget_trim_children(ctx, widget, items);
  for (i = widget_count_children(widget); i < items; i++) {
    /* 添加子控件(通过克隆原型得到的复制品) */
    widget_add_child(widget, binding_context_get_widget(ctx, widget));
  }
  return_value_if_fail(items == widget_count_children(widget), RET_OOM);

  return RET_OK;
}

list_view 中的子控件结构都相同,相较于使用 widget_fanctory ,通过原型模式 widget_clone 增加 list_view 子控件,其子控件无需再进行初始化配置(设置属性,添加子控件等)。

小结

适合应用场景

  • 如果需要复制一些对象,同时又希望代码独立于这些对象所属的具体类,可以使用原型模式。
  • 如果子类的区别仅在于其对象的初始化方式,那么可以使用该模式来减少子类的数量。别人创建这些子类的目的可能是为了创建特定类型的对象。

优点

  • 可以克隆预生成原型,避免反复运行初始化代码。
  • 可以克隆对象, 而无需与它们所属的具体类相耦合。
  • 更方便地生成复杂对象。
  • 可以用继承以外的方式来处理复杂对象的不同配置。

缺点

  • 克隆包含循环引用的复杂对象可能会非常麻烦。

参考

22种设计模式:refactoringguru.cn/design-patterns
AWTK:github.com/zlgopen/awtk
《设计模式:可复用面向对象软件的基础》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值