首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

两种public接口比较解决方法

2013-04-21 
两种public接口比较(1)[解决办法]仅从代码lz的两段代码上是看不出哪个好哪个坏的。只要记住设计的原则是,让

两种public接口比较
(1)


[解决办法]
仅从代码lz的两段代码上是看不出哪个好哪个坏的。
只要记住设计的原则是,让接口更容易被正确地使用,而不容易被错误地使用。
那几个设置项之间是互相独立的还是多选一的?如果是前者,建议用1;后者,可以用2,但函数名称要起得好点,如,SendTextAndSwitch2TheState。
[解决办法]
单一职责适用于接口、类,同时也适用于方法,什么意思呢?一个方法尽可能做一件事情,比如一个方法修改用户密码,不要把这个方法放到“修改用户信息”方法中,这个方法的颗粒度很粗.
个人倾向第一种
[解决办法]
(2)的做法当然比(1)好得多,但是,(2)还未足够好,以下做法比(2)更好:

class TF_BOLD_ITALICS;
class TF_BOLD;
class TF_ITALICS;


class TextHandler
{
public:

    template< typename T >
    void SendText( const std::string & msg );
};

template< >
inline void TextHandler::SendText< TF_BOLD_ITALICS >( const std::string& msg )
{
    std::cout << "TF_BOLD_ITALICS " << msg << std::endl;
}

template< >
inline void TextHandler::SendText< TF_BOLD >( const std::string& msg )
{
    std::cout << "TF_BOLD " << msg << std::endl;
}

template< >
inline void TextHandler::SendText< TF_ITALICS >( const std::string& msg )
{
    std::cout << "TF_ITALICS " << msg << std::endl;
}

int main( void )
{
    TextHandler A;
    A.SendText< TF_BOLD_ITALICS >( "kkkkkk" );
    A.SendText< TF_BOLD >( "yyyyyy" );
    A.SendText< TF_ITALICS >( "zzzzzzzz" );


    return 0;
}



楼主能看出好在什么地方么?
[解决办法]
 A.SendText< TF_BOLD_ITALICS >( "kkkkkk" );
 A.SendText_TF_BOLD( "yyyyyy" );
 A.SendText(TF_ITALICS, "zzzzzzzz" ); 
三种形式没有任何区别。
另外,dry根本不是来说怎么定义接口的。
[解决办法]
楼上再好好想想吧
[解决办法]
马克。、。。
[解决办法]

[解决办法]
Mark 坐观上面辩论
[解决办法]
template
enum
[解决办法]
单纯就这个接口而言,2比较好,但是追求不能过度。我曾经和同事说笑,世界有一个万能接口就够用了,那就是exec(void *),绝对能通用任何函数。
[解决办法]
单一职责原则,建议第一种
[解决办法]
第一种吧,第一种比较好维护,第二种当你的枚举类型很多的时候就很难维护了,其实可以两种结合,把第一种的函数声明为私有,第二种声明为公有,在第二种中针对不同的枚举类型调用第一种中的相应的函数。感觉这样可读性、可维护性和可扩展性都增强了。
[解决办法]


先从第一个说起吧。这几个成员函数其实是相同功能的函数,区别只不过是不同的字体,这个做法把不同字体的操作硬编码在TextHandler的接口中,需要增加新字体(及字体组合)就添加新的成员函数,减少字体就删除(或废弃)相应的成员函数,问题是,字体需求是相对容易发生变化的,容易造成TextHandler的接口一直处于不稳定的状态中。在软件设计时接口不稳定是个大问题,会牵连到不同的模块,应力求避免,另一方面,即使不使用的函数,也同样包含在程序中。总的来说就是设计不灵活、扩展难、维护难,当然也不是没有优点,最大的优点就是可读性,目的非常清晰,但得不偿失。



第二种做法将三个成员函数归纳为一个单一功能的函数,有更好的内聚性。字体需求变化时不需要修改TxtHandler的接口了,修改SendText的实现就行了,无论接口稳定性还是灵活性、扩展性、维护性都有较大提高。但是,仍存在两个缺点:

一、发生变化时需要修改SendText已有的代码,容易引入新的错误,同时增加了复杂性;
二、由于在SendText内部需要对format进行执行期判断,这需要使用连环条件选择或者fall through switch,对于CPU和编译器来说,这可是极其不愿意见到的情景,分支选择需要依赖CPU的分支预测命中率,对编译器来说也难以优化,总之一句话就是对性能产生了影响。如何既保持上述几个优点同时又避免这两个缺点?这就有了偶在8楼提出的解法。

偶把字体由枚举换成了类型,这就可以通过模板用编译期类型选择代替执行期条件选择,不需要在执行期判断format了,编译后就是需要的那个字体SendText了,提高了性能。另一方面,得益于模板的延迟实例化,只有用到的字体SendText才产生实例。扩展也非常容易,增加新的字体只需要添加该字体的特化,重要的是,不用改动已有的旧代码,避免增加代码复杂性和引入新错误。

当然,偶这个做法也有一个局限性,就是不适用于执行期才知道字体种类的情况,例如字体种类保存在文件或其它载体中,执行期读入字体种类再Send,这时候执行期条件选择无可避免。

最后再指出一点,上述几种做法都是侵入式的,至少更改了SendText的实现,通过policy等方法可以做到非侵入式设计,既不改动原有代码,又满足客户的不同需求。这方面一个常用的例子是STL的allocator,allocator就是一个policy,STL的客户可以设计自己的allocator,可以添加另外的功能,例如垃圾收集等,但STL的代码完全不用改动。
[解决办法]
围观学习两种public接口比较解决方法
[解决办法]

引用:
引用:引用:(2)的做法当然比(1)好得多,但是,(2)还未足够好,以下做法比(2)更好:

C/C++ code?123456789101112131415161718192021222324252627282930313233343536373839class TF_BOLD_ITALIC……

委托
[解决办法]
这几个都差不多, 主要取决于
1. 定义, 代码复杂度. 
2. 扩展, 以后新的接口要求
3. 封装, 每个类封装一个事情.

1. 如果复杂度还好. 例如仅仅是给字符串加几个前后缀. 例如<B><I>. 这几个接口都还好
2. 如果扩展要求比较高. 例如以后添加下划线, 什么的. 组合就多了. 最好用bit位来表示格式化内容

    enum TEXT_FORMAT
    {
        TF_BOLD = 1,
        TF_ITALICS = 2,
        TF_UNDERLINE = 4,
    }

        TF_BOLD_ITALICS_UNDERLINE = TF_BOLD  
[解决办法]
 TF_ITALICS 
[解决办法]
 TF_UNDERLINE;

又或者以后发送可能要发送图片什么的, 那么格式化就有必要独立为类, 而不是enum符号.

3. 如果发送文本的逻辑和格式化逻辑都比较复杂, 这两种事情可以分开. 格式化用单独的一个类. 参考GP中的Policy Based Class或者Strategy Pattern. 而组合的嵌套的格式化逻辑, 可以考虑Decorator Pattern
[解决办法]
class TextHandler
{
public:
    void SendText(const std::string & msg);
};

class BoldItalicsTextHandler : public TextHandler
{
    void SendText(const std::string & msg);
};

...

[解决办法]
让接口更好用,更不容易出错
顶一个。

热点排行