建造者(Builder)模式应用


前言

        软软件设计模式(Design pattern),简称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。--来自百度百科。
        既然设计模式有那么多好处,我们在做程序设计的时候,就应该充分考虑自己需要解决的问题是否有一个设计模式与之相似,尽量使用现有的解决方案来设计程序,避免代码重复或自己考虑不足导致设计缺陷。
        这篇博客是对这周写的一个练习题的一个总结,练习题中使用到了建造者模式,这里总结Builder模式的意图和实现要点,分享给需要学习这个模式的同学们。

一、Builder模式意图

        将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

二、C语言实现Builder模式

1.例子背景简介

        这周完成了一个练习题,练习题的目标是解析aidl文件,并转化成json字符串。我写的第一版程序,是边解析aidl文件,边生成json对象,解析和生成是交织在一起的。这种实现方式虽然能达到目的,但是,如果需求改变,不生成json,而是转化成别的文件格式时,我的代码复用率极低,而且无法从容的应对需求的改变,扩展性差,也不符合程序设计的开闭原则。

2、例子重新设计的思想

        aidl文件的解析是一个非常独立的工作,应该完全独立实现,不应该和他的消费者代码融合在一起。而且,aidl文件的格式非常固定,由Package、Import、Interface三部分组成,其中Interface是固定存在的,其他两个则是可选的。那么把aidl文件转换成其他的文件格式,转换流程也是相对固定的,包含Package、Import、Interface三部分的转换。转换的流程跟具体需要转换的格式是可以隔离开来的。这就满足了Builder模式的设计意图:构造和表示分离。我们可以把aidl分三个步骤来构建json文件,也可以使用相同的步骤重新格式化aidl文件,这就是构建和表示分离,把变化的,和不变的分离,达到了隔离变化,降低模块间耦合度的目的。

3、例子模块设计

        例子一共分成三个部分:aidl解析、aidl转换和json生成。其中aidl转换和json生成使用到的技术就是builder模式。这里只贴出转换和生成的源码,完整源码可以留言索取。

4、C语言代码实现

aidl转换代码: aidl_converter.h
/**
 * File:   aidl_converter.h
 * Author: AWTK Develop Team
 * Brief:  converte aidl to other
 *
 * Copyright (c) 2018 - 2020  Guangzhou ZHIYUAN Electronics Co.,Ltd.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * License file for more details.
 *
 */

/**
 * History:
 * ================================================================
 * 2020-12-09 zhang zhongji <zhangzhongji@zlg.cn> created
 *
 */
#ifndef AIDL_CONVERTER_H
#define AIDL_CONVERTER_H
#pragma once
#include "aidl_parser.h"

typedef void (*package_converter_t)(void* ctx, const char* package_name);
typedef void (*import_converter_t)(void* ctx, const char* class_name);
typedef void (*interface_converter_t)(void* ctx, const char* interface_name, function_component_t* function_component);
typedef char* (*result_t)(void* ctx);

typedef struct _v_table_t{
    package_converter_t package_converter;
    import_converter_t import_converter;
    interface_converter_t interface_converter;
    result_t get_result;
    void* ctx;
} v_table_t;

typedef struct _aidl_converter_t {
    v_table_t v_table;
    aidl_parser_t aidl_parser;
} aidl_converter_t;

/**
 * @method aidl_converter_init
 * 初始化aidl_converter对象。
 * @annotation ["constructor"]
 * @param {aidl_converter_t*} aidl_converter aidl_converter对象。
 * @param {char*} str 要转换的aidl字符串。
 * @param {v_table_t} v_table 转换方法的函数表。
 *
 * @return {aidl_converter_t*} aidl_converter对象本身。
 */
aidl_converter_t* aidl_converter_init(aidl_converter_t* aidl_converter, const char* str, v_table_t v_table);

/**
 * @method aidl_converter_converte
 * aidl转换成指定格式字符串。
 * @param {aidl_converter_t*} aidl_converter aidl_converter对象。
 *
 * @return {char* } 返回非NULL为成功,否则失败。
 */
char*  aidl_converter_convert(aidl_converter_t* aidl_converter);

/**
 * @method aidl_converter_deinit
 * 析构aidl_converter对象。
 * @annotation ["destructor"]
 * @param {aidl_converter_t*} aidl_converter aidl_converter对象。
 *
 * @return {ret_t*} 返回RET_OK表示成功,否则表示失败。
 */
ret_t aidl_converter_deinit(aidl_converter_t* aidl_converter);

#endif /*AIDL_CONVERTER_H*/

aidl_converter.c

/**
 * File:   aidl_converter.c
 * Author: AWTK Develop Team
 * Brief:  converte aidl to other
 *
 * Copyright (c) 2018 - 2020  Guangzhou ZHIYUAN Electronics Co.,Ltd.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * License file for more details.
 *
 */

/**
 * History:
 * ================================================================
 * 2020-12-26 zhang zhongji <zhangzhongji@zlg.cn> created
 *
 */
#pragma once
#include "aidl_converter.h"

aidl_converter_t* aidl_converter_init(aidl_converter_t* aidl_converter, const char* str, v_table_t v_table) {
    return_value_if_fail(aidl_converter != NULL && str != NULL, NULL);

    aidl_converter->v_table.package_converter = v_table.package_converter;
    aidl_converter->v_table.import_converter = v_table.import_converter;
    aidl_converter->v_table.interface_converter = v_table.interface_converter;
    aidl_converter->v_table.get_result = v_table.get_result;
    aidl_converter->v_table.ctx = v_table.ctx;

    const char* separtor = " ;\n{}()";
    aidl_parser_init(&aidl_converter->aidl_parser, str, strlen(str), separtor);
    return aidl_converter;
}

static void aidl_converter_convert_package(aidl_converter_t* aidl_converter) {
    return_if_fail(aidl_converter != NULL);
    
    const char* package_name = aidl_parser_first_package(&aidl_converter->aidl_parser);
    if (package_name != NULL) {
        aidl_converter->v_table.package_converter(aidl_converter->v_table.ctx, package_name);
    }
    
    const char* next_package_name = aidl_parser_next_package(&aidl_converter->aidl_parser);
    while (next_package_name != NULL)
    {
        aidl_converter->v_table.package_converter(aidl_converter->v_table.ctx, package_name);
        next_package_name = aidl_parser_next_package(&aidl_converter->aidl_parser);
    }

    return;
}

static void aidl_converter_convert_import(aidl_converter_t* aidl_converter) {
    return_if_fail(aidl_converter != NULL);
    
    const char* class_name = aidl_parser_first_import(&aidl_converter->aidl_parser);
    if (class_name != NULL) {
        aidl_converter->v_table.import_converter(aidl_converter->v_table.ctx, class_name);
    }
    
    const char* next_class_name = aidl_parser_next_import(&aidl_converter->aidl_parser);
    while (next_class_name != NULL)
    {
        aidl_converter->v_table.import_converter(aidl_converter->v_table.ctx, next_class_name);
        next_class_name = aidl_parser_next_import(&aidl_converter->aidl_parser);
    }

    return;
}

static void aidl_converter_convert_interface(aidl_converter_t* aidl_converter) {
    return_if_fail(aidl_converter != NULL);
    
    const char* interface_name = aidl_parser_interface_name(&aidl_converter->aidl_parser);
    if (interface_name != NULL) {
        function_component_t* next_function_component = aidl_parser_next_function(&aidl_converter->aidl_parser);
        while (next_function_component != NULL)
        {
            aidl_converter->v_table.interface_converter(aidl_converter->v_table.ctx, 
            interface_name, next_function_component);

            next_function_component = aidl_parser_next_function(&aidl_converter->aidl_parser);
        }
    }

    return;
}

static char* aidl_converter_get_result(aidl_converter_t* aidl_converter) {
    return_value_if_fail(aidl_converter != NULL, NULL);

    return aidl_converter->v_table.get_result(aidl_converter->v_table.ctx);
}

char* aidl_converter_convert(aidl_converter_t* aidl_converter) {   
    aidl_converter_convert_package(aidl_converter);
    aidl_converter_convert_import(aidl_converter);
    aidl_converter_convert_interface(aidl_converter);

    return aidl_converter_get_result(aidl_converter);
}

ret_t aidl_converter_deinit(aidl_converter_t* aidl_converter) {
    return RET_OK;
}

生成json的源码:json_builder.h
/**
 * File:   json_builder.h
 * Author: AWTK Develop Team
 * Brief:  create json
 *
 * Copyright (c) 2018 - 2020  Guangzhou ZHIYUAN Electronics Co.,Ltd.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * License file for more details.
 *
 */

/**
 * History:
 * ================================================================
 * 2020-12-27 zhang zhongji <zhangzhongji@zlg.cn> created
 *
 */

#ifndef JSON_BUILDER_H
#define JSON_BUILDER_H

#include "tkc/types_def.h"
#include "tkc/str.h"
#include "../3rd/cjson/cJSON.h"
#include "aidl_parser.h"

BEGIN_C_DECLS

typedef struct _json_ctx_t {
    cJSON* root;
    cJSON* package_array;
    cJSON* import_array;
    cJSON* interface_obj;
    cJSON* function_array;
} json_ctx_t;

void convert_package_to_json(void* ctx, const char* package_name);
void convert_import_to_json(void* ctx, const char* class_name);
char* aidl_2_json_converter_result(void* ctx);
void convert_interface_to_json(void* ctx, const char* interface_name, function_component_t* function_component);

END_C_DECLS

#endif /*JSON_BUILDER_H*/

json_builder.c

/**
 * File:   json_builder.c
 * Author: AWTK Develop Team
 * Brief:  create json
 *
 * Copyright (c) 2018 - 2020  Guangzhou ZHIYUAN Electronics Co.,Ltd.
 *
 * This program is ditokenizeributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * License file for more details.
 *
 */

/**
 * History:
 * ================================================================
 * 2020-12-27 zhang zhongji <zhangzhongji@zlg.cn> created
 *
 */
#include "json_builder.h"
#include "../3rd/cjson/cJSON.h"
#include "aidl_converter.h"

ret_t converte_param_to_json(void* ctx, const void* data) {
    return_value_if_fail(ctx != NULL && data != NULL, RET_BAD_PARAMS);
    cJSON* param_array = (cJSON*)ctx;
    
    cJSON *param_obj = cJSON_CreateObject();
    cJSON_AddItemToArray(param_array, param_obj);
    param_component_t* param_component = (param_component_t*)data;

    if (param_component->tag.size > 0) {
        cJSON_AddStringToObject(param_obj , "param_tag", param_component->tag.str);
    }
    
    if (param_component->param_type.size > 0) {
        cJSON_AddStringToObject(param_obj , "param_type", param_component->param_type.str);
    }
    
    if (param_component->param_name.size > 0) {
        cJSON_AddStringToObject(param_obj , "param_name", param_component->param_name.str);
    }
    
    return RET_OK;
}

static cJSON* converte_funtion_to_json(function_component_t* function_component) {
    return_value_if_fail(function_component != NULL, NULL);
    cJSON* function_obj = cJSON_CreateObject();

    if (function_component->return_type.size > 0) {
        cJSON_AddStringToObject(function_obj , "return_type", function_component->return_type.str);
    }

    if (function_component->function_name.size > 0) {
        cJSON_AddStringToObject(function_obj , "function_name", function_component->function_name.str);
    }

    cJSON* param_array = cJSON_CreateArray();
    ret_t ret = slist_foreach(function_component->param_list, converte_param_to_json, param_array);
    cJSON_AddItemToObject(function_obj , "param_list", param_array);
    
    return function_obj;
}

void convert_package_to_json(void* ctx, const char* package_name) {
    return_if_fail(ctx != NULL && package_name != NULL);

    json_ctx_t* json_ctx = (json_ctx_t*)ctx;
    if (json_ctx->package_array == NULL) {
        json_ctx->package_array = cJSON_CreateArray();
        cJSON_AddItemToObject(json_ctx->root, "package", json_ctx->package_array);
    }

    cJSON_AddItemToArray(json_ctx->package_array, cJSON_CreateString(package_name));
}

void convert_import_to_json(void* ctx, const char* class_name) {
    return_if_fail(ctx != NULL && class_name != NULL);

    json_ctx_t* json_ctx = (json_ctx_t*)ctx;
    if (json_ctx->import_array == NULL) {
        json_ctx->import_array = cJSON_CreateArray();
        cJSON_AddItemToObject(json_ctx->root, "import", json_ctx->import_array);
    }

    cJSON_AddItemToArray(json_ctx->import_array, cJSON_CreateString(class_name));
}

void convert_interface_to_json(void* ctx, const char* interface_name, function_component_t* function_component) {
    return_if_fail(ctx != NULL && NULL != interface_name && function_component != NULL);

    json_ctx_t* json_ctx = (json_ctx_t*)ctx;
    if (json_ctx->interface_obj == NULL) {
        json_ctx->interface_obj = cJSON_CreateObject();
        json_ctx->function_array = cJSON_CreateArray();
        cJSON_AddStringToObject(json_ctx->interface_obj, "interface_name", interface_name);
        cJSON_AddItemToObject(json_ctx->interface_obj, "function_array", json_ctx->function_array);
        cJSON_AddItemToObject(json_ctx->root, "interface", json_ctx->interface_obj);
    }

    cJSON* function_obj = converte_funtion_to_json(function_component);
    cJSON_AddItemToArray(json_ctx->function_array, function_obj);
}

char* aidl_2_json_converter_result(void* ctx) {
    return_value_if_fail(ctx != NULL, NULL);
    json_ctx_t* json_ctx = (json_ctx_t*)ctx;

    char* out = cJSON_Print(json_ctx->root);
    cJSON_Delete(json_ctx->root);
    return out;
}

相当于main函数的调用方式:

/**
 * File:   aidl_2_json_converter.c
 * Author: AWTK Develop Team
 * Brief:  convert aidl to json
 *
 * Copyright (c) 2018 - 2020  Guangzhou ZHIYUAN Electronics Co.,Ltd.
 *
 * This program is ditokenizeributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * License file for more details.
 *
 */

/**
 * History:
 * ================================================================
 * 2020-12-09 zhang zhongji <zhangzhongji@zlg.cn> created
 *
 */
#pragma once
#include "aidl_2_json_converter.h"
#include "aidl_parser.h"
#include "../3rd/cjson/cJSON.h"
#include "aidl_converter.h"
#include "json_builder.h"

char* aidl_2_json_converter_convert(const char* aidl_file) {
    return_value_if_fail(aidl_file != NULL, NULL);
    
    json_ctx_t* json_ctx = (json_ctx_t*)malloc(sizeof(json_ctx_t));
    json_ctx->root = cJSON_CreateObject();
    json_ctx->package_array = NULL;
    json_ctx->import_array = NULL;
    json_ctx->interface_obj = NULL;
    json_ctx->function_array = NULL;

    v_table_t v_table;
    v_table.package_converter = convert_package_to_json;
    v_table.import_converter = convert_import_to_json;
    v_table.interface_converter = convert_interface_to_json;
    v_table.get_result = aidl_2_json_converter_result;
    v_table.ctx = json_ctx;

    aidl_converter_t aidl_converter;
    aidl_converter_t* c = aidl_converter_init(&aidl_converter, aidl_file, v_table);
    char* result = aidl_converter_convert(c);
    aidl_converter_deinit(c);

    free(json_ctx);
    return result;
}

总结

C语言的代码是使用C++面向对象的方式写的,这里使用到的技术总结一下:

1、aidl的转换模块使用到了函数指针技术和C++的虚函数表思想;

2、aidl的转换模块使用了分步构造技术,利用函数指针把构造过程和实际构造实现分离;

3、json的生成使用到了cJson库,想学习这个库的同学可以仔细研究一下里面的接口;

4、aidl的解析代码使用了分步解析方式,可以方便消费者独立获取需要的内容(源码未提供,可以参照这里的调用方式了解解析的接口设计思想)
5、代码的实现使用了AWTK的str库和slist库,想学习这两个库的源码的同学可以从李老师的AWTK开源项目里找到:AWTK

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值