前言
软软件设计模式(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