一种通用的接口设计方案

原创 2005年03月02日 08:13:00

1.1       背景

目前的XXXX扩展接口定义如下:

class ProductProcesser

{

public:

       virtual long process(const in_type&,out_type&) = 0;

       …. //还有其他扩展接口也定义在一起

}

讨论集中在上面process成员函数的定义。因为产品需求的变化,目前的process函数需要在两种情况下调用,因此考虑两种修改方案:

1)修改process为:long (int flag,const in_type&,out_type&)

flag代表不同应用场合

2)定义不同名字的虚函数

3)修改process为long process(int flag,void* in_pData,void* out_pdata) = 0;这种方式意图是支持不同处理参数

我们都希望这次改动之后系统的可扩展性更好

1.3       分析

首先说明,每种设计方案都有自己的优缺点,不存在一个最好的方案。只能依据软件设计的一些基本原则来分析一个设计是否有改善的余地,

1.            看接口类ProductProcess的定义,因为包含多种处理业务的扩展接口,这些扩展接口之间基本上没有关系,是松散耦合的,很显然违背了ISP(接口分离原则)

2.           long (int flag,const in_type&,out_type&)的定义,首先要求平台和产品在处理flag参数上保持一致,但只是口头或文档约定,无法避免实际代码中出现不一致的情况,造成平台和产品代码之间的紧耦合。另外针对各种业务处理流程都要求在同一个接口中实现,一旦某个业务接口发生变动,将对其他业务接口的实现造成影响,个人认为很明显违背OCP(开放封闭原则)

3.         long process(int flag,void* in_pData,void* out_pdata)的定义,想实现任意扩展业务处理接口,而且对业务处理数据的类型不限制,但实际上也无法做到,因为某个业务处理接口可能有1个参数,也可能有多个参数,对于后者,还需要包装多个参数,使用不方便,关键是利用void*传递各种数据不是类型安全的,C++中应该慎用。

1.4       考虑

能够用一种更好的方式实现long process(int flag,void* in_pData,void* out_pdata)的设计意图,甚至增强其适应范围,即对参数个数和类型都不加限制。当然是用面向对象的思想方式,通过接口,继承等技术来实现。看起来肯定比单纯的一个成员函数复杂得多,但更灵活,甚至可以统一任意扩展接口的实现方式。

1.5       我的实现方式

因为各个业务处理的参数类型,参数个数都是不同的,无法通过一个接口来定义所有的业务处理,考虑一个退化的接口类型的实现方式,如下:

ExpandInterface做为任何扩展接口的基类定义,只是提供一个类型表示,具体业务处理接口有其子接口定义, 二次开发人员的具体实现是这些子接口的子类。比如,上面分别为同步告警和接受实时告警定义了不同的子接口。这两个子接口从形式上看是一摸一样的,为什么不统一呢?我认为这里只是接口定义,重复代码可以忽略不计;他们的行为方式是不同的,定义不同的接口名非常容易理解,这样的代码可以说是自注释的;两种告警业务处理本来不相关,分开之后可以独立变化对另一个没有任何影响。从以上三方面考虑,分开定义更好。

另外,平台应该提供一个供二次开发人员设置其实现类的接口,提供这样一个扩展接口的管理类:

ExpandManager是平台提供的一个实现类,二次开发人员直接使用,它只能看到ExpandInterface接口。

对于平台开发人员来讲,就存在一个问题,它是怎么知道某个ExpandInterfaceRealAlmInterface还是SynAlmInterface呢?因为ExpandManager,ExpandInterface, RealAlmInterface, SynAlmInterface都是平台定义并实现的,从技术上讲,平台开发人员可以利用dynamic_cast转换每个ExpandInterface进行尝试,最终找到自己需要的接口。

很遗憾,我们无法利用typeid来实现ExpandManager::add(ExpandInterface*)

void add(ExpandInterface* p){

_map[typeid(*p).name()] = p; //直接对一个指针类型使用typeid不能得到其真实的子类类型

}

我们无法通过typeid(*p)来获取中间层次(这里的RealAlmInterface,SynAlmInterface)的类型信息。

为了避免在平台内部频繁使用dynamic_cast,我们需要在ExpandInterface接口上增加能够判断子接口类型的功能,很容易想到的方法如下:

class ExpandInterface

{

public:

       virtual int getProtocol() = 0;

};

class RealAlmInterface: public ExpandInterface

{

       virtual int getProtocl() { return REAL_ALM_PROCESSOR; }

};

要求平台为定义的每个业务处理接口,也就是ExpandInterface的子类实现getProtocol纯虚接口,这样ExpandManager::add(ExpandInterface*)的实现就非常简单了:

void add(ExpandInterface* p){    _map[p->getProtocl()] = p; }

通过这种方式平台开发人员也很容易获取某个业务处理接口,新增业务处理接口只需要在平台定义的时候保证其业务标识是唯一的,不重复的即可,与二次开发也没有任何关系。

但是这种方法的确还存在一个比较大的缺点,无法避免二次开发人员也重载了getProtocl接口并返回不同的值,这种重载可能是恶意的,也可能是无意的。为了避免这种情况,我们需要提供文档解释说明二次开发人员不要重载这个接口,但无法保证实际代码中会发生什么。

我们需要一个ExpandInterface中定义的接口,平台可以使用,可以修改,产品无法使用也无法修改,visitor模式可以帮助我们做到这一点。

业务类型也就是每个ExpandInterface的子类的类型信息保存在Visitor类中。二次开发人员无法修改RealAlmInterface::accept接口的关键之处是平台不对外公布Visitor类的定义,只是在ExpandInterface的定义文件中使用Visitor类的前向声明即可,这样二次开发人员多能做的事情就是实现一个空的accept函数,这样,在平台实现代码的时候,调用accept之前赋予Visitor一个合理缺省值,能够检测到这种情况,给出拒绝或警告提示,总之一切又都在平台的控制之下。

1.6       完整类图

对外提供接口:

ExpandInterface, RealAlmInterface,SynAlmInterface

对外提供的实现体,直接使用:

ExpandManager

只对内提供的定义:

Visitor

二次开发需要实现的:

ConcretRealAlm, ConcretSynAlm

1.7       其他考虑

有的业务允许多个扩展接口串行处理,这种方式的支持不建议在ExpandManagerExpandInterface层面进行改动,而是将ExpandInterface的子类,即业务处理接口设计为职责链模式(chain of responsibility),同时结合模板方法(template method)即可:

这种通用接口的设计可以用于任何需要扩展处理的地方,平台和二次开发人员之间只需要通过不会产生任何歧义的接口进行交互,而且避免二次开发人员无意或恶意的错误.

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

浅谈web架构之架构设计

前言 题目有点大,所以不可能说得非常具体,笔者也不能驾驭全部。 前面介绍过网站发展过程中架构的演化过程,本文主要针对网站架构各个方面的建设进行简单介绍。 架构模式 先来说说模式...

前后端分离架构中的接口设计

前后端分离一般是指在软件开发过程中,前端代码和后端代码分别开发,通过HTTP接口的方式进行通信,前后端分离架构分增加沟通成本,而沟通中最重要的一块就是前端与后端的接口设计。

接口应该如何设计

以前我们就知道什么哲学,哲学是关于世界观的学说,是系统化、理论化的世界观,而世界观是人们对整个世界的总体看法和基本观点。方法论是人们认识事物、改造世界的根本方法。由此可见,我们无论做什么也是根据自己的...

第三方接口开发规范

一、前言        最近公司业务需要希望能够连接东亚银行的接口直接对商家进行转账付款,但由于前期可行性研究的准备工作没有做好,导致在开发进入两周后才发现原先的设计存在重大安全漏洞,不得不停止...

关于RESTful一些注意事项,和自己整理的接口开发规范

最近在研究restful,公司开发要使用,所以自己就去网上找了好些资料,并整理了一套公司开发的接口规范。当然,我也只是刚刚入坑。还不是很全面。但是这就是一个过程。一点点,总会好起来的。以下是就是RES...

服务端 API 接口设计最佳实践

在移动互联网开发领域,我们经常需要针对移动设备,提供数据访问接口。在移动时代以前,接口设计并没有面对这么大的挑战,因为那时期的应用开发,前后端的区分并没有那么明显,需要专门设计接口的场景并不是很多。 ...
  • xsl_bj
  • xsl_bj
  • 2015-09-07 16:49
  • 1874

api接口设计

写过不少接口,不过一直没有去总结,网上搜了一下,大同小异,此文根据以下几个链接整理修改: https://segmentfault.com/a/1190000004051246 http://blog...

微服务RESTful 接口设计规范

1、RESTful发展背景及简介 网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备......)。因此,必须有一种统一的机制,方便不同的...

架构设计--用户端全http参数接口详细说明v1

1. 用户端全http参数接口详细说明v1.doc 1 2. change histor 1 3. 接口通用参数说明 1 4. 函数注册接口(规划中) 3 5. 用户权限模块 3 5.1. ...

App架构设计之接口

App架构设计经验谈:接口的设计   App与服务器的通信接口如何设计得好,需要考虑的地方挺多的,在此根据我的一些经验做一些总结分享,旨在抛砖引玉。 安全机制的设计 现在,...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)