两种public接口比较

zhuyf87 2013-04-11 03:30:34
(1)
class TextHandler
{
public:
void SendBoldItalicsText(const std::string & msg);
void SendBoldText(const std::string & msg);
void SendItalicsText(const std::string & msg);
void SendText(const std::string & msg);
...
}


(2)
class TextHandler
{
public:
enum TEXT_FORMAT
{
TF_BOLD_ITALICS,
TF_BOLD,
TF_ITALICS,
}

void SendText(const std::string & msg, TEXT_FORMAT format);
...
}


(1)和(2)两种接口设计,哪种更好?
我记得好像看到过QT提倡(1),今天看到某本书上写到(1)有违DRY(Don't Repeat Yourself)原则。
朋友们随便说说,我虚心听听。谢谢哈。
...全文
593 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
tommwq 2013-04-14
  • 打赏
  • 举报
回复
引用 23 楼 supermegaboy 的回复:
引用 20 楼 zhuyf87 的回复:引用 8 楼 supermegaboy 的回复:(2)的做法当然比(1)好得多,但是,(2)还未足够好,以下做法比(2)更好: C/C++ code?123456789101112131415161718192021222324252627282930313233343536373839class TF_BOLD_ITALIC……
委托
alex_my 2013-04-14
  • 打赏
  • 举报
回复
让接口更好用,更不容易出错 顶一个。
zhaokai115 2013-04-14
  • 打赏
  • 举报
回复
class TextHandler { public: void SendText(const std::string & msg); }; class BoldItalicsTextHandler : public TextHandler { void SendText(const std::string & msg); }; ...
笨蛋糕 2013-04-14
  • 打赏
  • 举报
回复
围观学习
zhuyf87 2013-04-14
  • 打赏
  • 举报
回复
引用 23 楼 supermegaboy 的回复:
引用 20 楼 zhuyf87 的回复:引用 8 楼 supermegaboy 的回复:(2)的做法当然比(1)好得多,但是,(2)还未足够好,以下做法比(2)更好: C/C++ code?123456789101112131415161718192021222324252627282930313233343536373839class TF_BOLD_ITALIC……
向大侠学些!
youyou1912 2013-04-14
  • 打赏
  • 举报
回复
这几个都差不多, 主要取决于 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
mujiok2003 2013-04-13
  • 打赏
  • 举报
回复
这两种都是c的做法,一般来说可以混合使用,以避免重复代码.用户更喜欢记住有意义的函数名字而不是记住不同的枚举值。

SendBoldItalicsText(const std::string & msg)
{
  SendText(const std::string & msg, TF_BOLD_ITALICS|TF_BOLD);
}
C++用重载,本质同第一种。

struct BoldTag{};
SendText(std::string& message,BoldTag)
{
   sendText(msg, TF_BOLD);
}
SendText(std::string& message)
{
   sendText(msg, TF_NORMAL);
}
//内部实现,可以不对外公开
SendText(const std::string & msg, TEXT_FORMAT format);


jdwx 2013-04-13
  • 打赏
  • 举报
回复
木有发现Qt里有(1)那样的函数,相反(2)那样的到处都是。
zhuyf87 2013-04-13
  • 打赏
  • 举报
回复
引用 8 楼 supermegaboy 的回复:
(2)的做法当然比(1)好得多,但是,(2)还未足够好,以下做法比(2)更好: C/C++ code?123456789101112131415161718192021222324252627282930313233343536373839class TF_BOLD_ITALICS;class TF_BOLD;class TF_ITALICS; class Tex……
supermegaboy 大侠,我想听您讲讲这种基于模板的接口的优点有哪些。非常感谢。^_^
飞天御剑流 2013-04-13
  • 打赏
  • 举报
回复
引用 20 楼 zhuyf87 的回复:
引用 8 楼 supermegaboy 的回复:(2)的做法当然比(1)好得多,但是,(2)还未足够好,以下做法比(2)更好: C/C++ code?123456789101112131415161718192021222324252627282930313233343536373839class TF_BOLD_ITALICS;class TF_BOLD;clas……
这两天有点忙 先从第一个说起吧。这几个成员函数其实是相同功能的函数,区别只不过是不同的字体,这个做法把不同字体的操作硬编码在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的代码完全不用改动。
zh6335901 2013-04-12
  • 打赏
  • 举报
回复
单一职责原则,建议第一种
zhuyf87 2013-04-12
  • 打赏
  • 举报
回复
引用 8 楼 supermegaboy 的回复:
(2)的做法当然比(1)好得多,但是,(2)还未足够好,以下做法比(2)更好: C/C++ code?123456789101112131415161718192021222324252627282930313233343536373839class TF_BOLD_ITALICS;class TF_BOLD;class TF_ITALICS; class Tex……
大侠能说说,为什么用这种member template 的设计更好呢?谢谢。
bravery36 2013-04-12
  • 打赏
  • 举报
回复
单纯就这个接口而言,2比较好,但是追求不能过度。我曾经和同事说笑,世界有一个万能接口就够用了,那就是exec(void *),绝对能通用任何函数。
tommwq 2013-04-12
  • 打赏
  • 举报
回复
引用 8 楼 supermegaboy 的回复:
(2)的做法当然比(1)好得多,但是,(2)还未足够好,以下做法比(2)更好: C/C++ code?123456789101112131415161718192021222324252627282930313233343536373839class TF_BOLD_ITALICS;class TF_BOLD;class TF_ITALICS; class Tex……
这个法子好。 把文本封装成TextWithStyle怎么样? Text t = "hello, world"; TextWithStyle tws(t, TextStyle::BOLD || TextStyle::ITALICS); SendText(tws);
sduxiaoxiang 2013-04-12
  • 打赏
  • 举报
回复
template enum
czjsai1989 2013-04-12
  • 打赏
  • 举报
回复
第一种吧,第一种比较好维护,第二种当你的枚举类型很多的时候就很难维护了,其实可以两种结合,把第一种的函数声明为私有,第二种声明为公有,在第二种中针对不同的枚举类型调用第一种中的相应的函数。感觉这样可读性、可维护性和可扩展性都增强了。
ken_scott 2013-04-11
  • 打赏
  • 举报
回复
Mark 坐观上面辩论
taodm 2013-04-11
  • 打赏
  • 举报
回复
引用 10 楼 supermegaboy 的回复:
楼上再好好想想吧
该想的是你
dahaiI0 2013-04-11
  • 打赏
  • 举报
回复
马克。、。。
飞天御剑流 2013-04-11
  • 打赏
  • 举报
回复
楼上再好好想想吧
加载更多回复(9)

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧