AWTK工厂模式--符合开闭原则的工厂模式

博客主要汇总了工厂模式,包括简单工厂模式、工厂方法模式和抽象工厂模式,还介绍了AWTK的改进工厂模式,包含该改进模式的简介以及C语言代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

        软软件设计模式(Design pattern),简称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。--来自百度百科。
        既然设计模式有那么多好处,我们在做程序设计的时候,就应该充分考虑自己需要解决的问题是否有一个设计模式与之相似,尽量使用现有的解决方案来设计程序,避免代码重复或自己考虑不足导致设计缺陷。
        近期在学习李老师的[AWTK](https://github.com/zlgopen/awtk) 源码,感觉受益匪浅,可以从中学习非常多的编程知识。这篇博客主要讲述的是AWTK里使用到的改进版本的工厂模式,它和书上和网上资料描述的工厂模式都不同,代码的设计是满足开闭原则的,而一般的书中或网上的工厂模式并不满足开闭原则,对于扩展并不友好。

一、工厂模式简单汇总

        我们在书中或是在网上资料中的工厂模式包括:简单工厂模式、工厂方法模式以及抽象工厂模式,这里对这三种模式做一个简单的汇总。

1.简单工厂模式

        简单工厂模式我也有写过一篇博客([简单工厂模式](https://blog.csdn.net/woody218/article/details/109563187)),有兴趣的同学可以点链接查看。简单工厂模式只是对于对象的创建做了一层简单的封装,根据类型创建需要的对象。工厂对象必须要知道所有类型对象的创建方法,根据创建时传入的类型决定创建哪种类型的对象。这种方法只适合少数对象的创建,如果需要创建大量类型的对象,工厂类会显得非常臃肿,而且对扩展也不友好,每增加一种类型对象的创建,都需要修改工厂类,并不满足程序设计的开闭原则。

2.工厂方法模式

        工厂方法模式的思想是:把产品和工厂分别抽象,由不同的工厂创建相对应的产品。这种方法,每增加一种产品的生产,需要增加一个具体产品类和一个具体工厂类。这样的设计虽然能解决简单工厂模式的中,工厂模式必须知道每一种对象的创建方法的缺点,但是工厂方法也有自己的缺陷,具体的工厂只负责一种具体产品的生产,如果需要生成新的类型,必须新建一个与新类型对应的新工厂,如果现实生活中的工厂也这样干,每增加一种产品的生产,就去新建一个新工厂,老板早破产了。具体工厂只负责一个具体产品的生产,无法应对新产品做扩展,也不符合程序设计的开闭原则。

3.抽象工厂模式

        抽象工厂模式是对工厂方法模式的一个扩展,它使得一个具体工厂可以生产多种具体的产品。但是,这又回到了简单工厂模式当中,工厂类必须知道所有对象的创建方法,每新增一类对象的创建,就需要修改代码去适应新增的创建需求,显然是不符合开闭原则的。

二、AWTK的改进工厂模式

1.改进的工厂模式简介

        AWTK对工厂模式做了一些改进,采用注册的方式,把工厂类和产品类隔离开来。工厂类负责统一的创建,根据创建时设置的创建协议,使用这个协议注册的创建方法去创建对象。这样,工厂类不需要知道具体产品的创建方法,也不需要知道他需要支持哪些类型的对象的创建,可以非常轻松的支持新产品的创建,而不需要修改工厂类,这样的设计就符合了程序设计中的开闭原则,对扩展开放,对修改闭合。

2.C语言代码实现

        李老师设计的数据读取器工厂类就是使用改进后的工厂模式设计的,以下是工厂类的提供的接口设计及其源码,我们可以在开源仓库中找到这些源码([AWTK](https://github.com/zlgopen/awtk))(源码路径:awtk/src/tkc/data_reader_factory.h、awtk/src/tkc/data_reader_factory.c)。这里为了介绍改进工厂模式的实现,省略了注释和源码,需要完整代码的同学可以移步到开源仓库中查看。 data_reader_factory.h接口设计如下:
typedef data_reader_t* (*data_reader_create_t)(const char* args);

/**
 * @class data_reader_factory_t
 * data reader工厂。
 *
 */
typedef struct _data_reader_factory_t {
  /*private*/
  darray_t creators;
} data_reader_factory_t;

/**
 * @method data_reader_factory
 * 获取缺省的data reader工厂对象。
 * @annotation ["constructor"]
 * @return {data_reader_factory_t*} 返回data reader工厂对象。
 */
data_reader_factory_t* data_reader_factory(void);

/**
 * @method data_reader_factory_set
 * 设置缺省的data reader工厂对象。
 * @param {data_reader_factory_t*} factory data reader工厂对象。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t data_reader_factory_set(data_reader_factory_t* factory);

/**
 * @method data_reader_factory_create
 * 创建data reader工厂对象。
 * @annotation ["constructor"]
 *
 * @return {data_reader_factory_t*} 返回data reader工厂对象。
 */
data_reader_factory_t* data_reader_factory_create(void);

/**
 * @method data_reader_factory_register
 * 注册data reader创建函数。
 * @param {data_reader_factory_t*} factory reader工厂对象。
 * @param {const char*} protocol 协议(如file)。
 * @param {data_reader_create_t} create data reader创建函数。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t data_reader_factory_register(data_reader_factory_t* factory, const char* protocol,
                                   data_reader_create_t create);
/**
 * @method data_reader_factory_create_reader
 * 创建指定类型的data reader对象。
 * @annotation ["constructor"]
 * @param {data_reader_factory_t*} factory data reader工厂对象。
 * @param {const char*} url URL。
 *
 * @return {data_reader_t*} 返回data reader对象。
 */
data_reader_t* data_reader_factory_create_reader(data_reader_factory_t* factory, const char* url);

/**
 * @method data_reader_factory_destroy
 * 析构并释放data reader工厂对象。
 * @param {data_reader_factory_t*} factory data reader工厂对象。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t data_reader_factory_destroy(data_reader_factory_t* factory);

END_C_DECLS

#endif /*TK_DATA_READER_FACTORY_H*/

接口设计简要说明:
1、工厂类提供了一个容器:darray_t creators,专门存储具体产品的信息,包括产品的协议和产品的创建方法等;
2、通过data_reader_factory_register接口,可以注册一个新的产品,使工厂能够创建新注册的产品,产品的信息存储到容器creators当中;
3、通过data_reader_factory_create_reader接口,可以创建具体的产品,产品的协议可以通过参数url指定。
4、具体产品的实例源码,可以从这个[路径](https://github.com/zlgopen/awtk)下的(awtk/src/tkc/data_reader_file.h)可以找到。
        通过以上接口设计,我们发现,工厂类和具体产品对象是分离的,工厂类做到了隔离变化,又很好的支持了扩展,完美的实现了程序设计的开闭原则。

总结

        通过对李老师的[AWTK](https://github.com/zlgopen/awtk)改进工厂模式的接口设计及源码学习,可以知道书上和网上资料的一些知识已经跟不上技术发展要求了,我们如果想把编程技术提高,仅仅看书和查资料是不够的,还需要思考一下,这些资料和技术,是否满足当前程序设计的基本原则,如果不满足,我们是否可以想办法进行改进,使其满足软件的设计原则。古语云:学而不思则罔,思而不学则殆,我们需要不断的更新技术知识,也同样需要不断的思考技术的优劣,从思考和实践中,不断的提升自己的编程水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值