接口编程和重构.

客户的需求永远在变,客户永远不知道具体想要什么,只想要好的.

就像买衣服一样,你只想买又便宜又好看的衣服,作为客户的你,其实并知道具体应该怎样设计衣服,却会提出颜色要亮一点,袖子要长一点。如何应变不断变化的需求,从销售到管理有一套方法学, 软件开发方面也有敏捷等方法学,现在我们从代码的角度讲如何应对这种变化。

 

编程的不二法则 -- 基于接口编程和重构。

 

举个例子,MP3播放器.

 

1. 最开始我们想到的:

我们想到的首先是创建一个Player的类:

class CMP3Player

{

public:

    CMP3Player();

    ~CMP3Player();

    int Play(const char* fileName);

    int Pause();

    int Stop();

    int GetPos() const;

    int SetPos(const int pos);

    int GetVolumn() const;

    int SetVolumn() const;

    .....// 其他的播放器方法

};

 

然后,就只要在各个方法中调用解码器的函数(对于Win平台有MDC系列可以用).好了,客户需求变了,我现在要放AVI格式的,怎么办?再写一个AVIPlayer吗?

 

2. 一点改进

所以,我们首先引入一个IPlayer的接口类,然后让MP3Player和AVIPlayer继承它:

class IPlayer

{

public:

     virtual ~IPlayer() {}

     virtual int Play(const char* fileName) = 0;

     virtual int Pause() = 0;

     virtual int Stop() = 0;

     ...

 

protected:

     IPlayer(){//做一些公共的初始化工作}

};

 

class MP3Player: public IPlayer

{

... // 实现IPlayer的接口

};

 

class AVIPlayer: publlic IPlayer

{

.... // 实现IPlaye的接口

};

 

3. 继续改进

看起来差不多了,其实不然,因为你写着写着,你就会发现其实无论是MP3Player还是AVIPlayer的播放逻辑都差不多,越往后写,只是不断在拷贝代码而已,真正区别的地方

只是调用了不同的解码器函数。

于是,我们需要抽取一个解码器类 --- IDecoder,它主要负责封装媒体库,同样它也是一个

接口。

class IDecoder

{

public:

    virtual int OpenStream(int handle) = 0;

    virtual int CloseStream(int handle) = 0;

    virtual int Play(int handle, HWND hWnd) = 0;

    virtual int InputData(int handle, void* buf, int bufSize) = 0;

    ....

};

 

class MP3Decoder: public  IDecoder {...}

class AVIDecoder: public IDecoder {...}

 

现在我们看看IPlayer应该是什么样子的:

class IPlayer

{

public:

    virtual ~IPlayer() = 0;

     virtual int Play(const char* fileName) = 0;

     virtual int Pause() = 0;

     virtual int Stop() = 0;

     ...

 

protected:

     IPlayer(){//做一些公共的初始化工作}

 

protected:

    IDecoder* m_pDecoder;

};

 

OK,我们已经不需要什么MP3Player或者AVIPlayer了,我们只需要一个FilePlayer就可以了.

class FilePlayer: public IPlayer {...},它会根据文件类型来创建不同的IDecoder.

 

4. 满足更多的需求

现在 客户又有需求了,除了播放本地文件外,还要支持实时播放,这时候我们只需要些一个

class VODPlayer: public IPlayer就可以了,需要注意的是,实时播放也有各种各样的协议,

或者是Rtsp,或者是MMST,对了,需要给协议做一个接口

class IProtocol

{

public:

     virtual int Start() = 0;

     virtual int Stop() = 0;

     virtual int OnReceiveData(void* data, int size) = 0; // 一般是回调函数

};

 

class RtspProtocol: public IProtocol {...}

class MMSTProtocol: public IProtocol {...}

这时候我们的VODPlayer会变成下面的样子:

class VODPlayer: public IPlayer

{

public:

    .... // 实现IPlayer的接口

 

protected:

    IProtocol* m_pProtocol;

};

 

5.一点总结

上 面改进的代码有很多,比如还可以引入Factory和Strategy等设计模式,就是由DecoderManager和PlayerManager来负 责创建和维护各种各样Decoder和 Player;甚至解码器的可以做成动态加载的方式,用插件化进行管理,等等。但是有了一个定义良好的接口,做其他事情都简单。

 

代码最重要的是正确性。那么,除了正确性以外呢?不是效率,不是性能,而是可扩展性和可

读性;以前设计精良的代码可能现在一团糟,我们需要做的是不断的重构。

 

现在已经不是K&R的时代(一个人写出C编译器和Unix操作系统)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值