枚举对比转换思路

枚举对比转换思路

需求分析

在Android系统开发中,我们经常会有这样的需求:
a. 首先,我们会在代码中定义许多配置类型,如定义音频输出设备,耳机、扬声器、蓝牙音箱等等,你会想到用枚举,如下:

enum audio_device_t {
    AUDIO_DEVICE_OUT_EARPIECE,
    AUDIO_DEVICE_OUT_SPEAKER,
    ....
};

b. 其次,我们在使用时会配置我们的输出设备,你可以在代码或者xml配置文件中配置,通常我们使用时,不一定和定义enum类型一致,如下:

<devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink"/>

c. 最后,我们会提取xml配置的type字符串类型,去我们定义的enum audio_device_t对比查找,找到我们配置选项,比较简单的做法可以像这么做

struct AudioDevice {
    const char *name;
    audio_device_t value;
}

const AudioDevice devices[] = {{"AUDIO_DEVICE_OUT_EARPIECE", AUDIO_DEVICE_OUT_SPEAKER},
                                {"AUDIO_DEVICE_OUT_SPEAKER", AUDIO_DEVICE_OUT_SPEAKER}};

audio_device_t compareAudioDevice(std::string &device){
    for(int i = 0; i < sizeof(devices)/sizeof(devices[0]); i++){
        if(strcmp(devices[i].name, device.c_str()) == 0){
            return devices[i].value;
        }
    }
    return null;
}

如果系统配置数量在少数的话,这样写法是没问题的,如果配置很多,从代码上来看会产生很多重复的代码,主要是compareAudioDevice对比方法比较多,如果减少冗余代码呢?肯定是用模板来减少,Android系统的TypeConvert类就是来做这个事情的,它把上面c步骤里面的属性和方法都封装在一个类里面如下:

template <class Traits>
class TypeConverter
{
public:
    //对比方法str是传入的key, result是查找后返回的结果
    static bool fromString(const std::string &str, typename Traits::Type &result){
        for (size_t i = 0; mTable[i].literal; i++) {
        if (strcmp(mTable[i].literal, str.c_str()) == 0) {
            ALOGV("stringToEnum() found %s", mTable[i].literal);
            result = mTable[i].value;
            return true;
            }
        }
        return false;
    }
    ......

protected:
    //枚举类型字符串和值的对应关系结构体
    struct Table {
        const char *literal;
        typename Traits::Type value;
    };
    //存储对应关系的数组
    static const Table mTable[];
};

只看上面可能还不是很懂,TypeConverter相当于最上面抽象的一层,还需要看以下具体的定义:

template <typename T>
struct DefaultTraits
{
    typedef T Type;
    ....
};
using DeviceTraits = DefaultTraits<audio_device_t>;
struct OutputDeviceTraits : public DeviceTraits {};
typedef TypeConverter<OutputDeviceTraits> OutputDeviceConverter;

DeviceTraits声明了泛型是audio_device_t,也就是我们的配置定义项,为什么这么做,因为在DefaultTraits我们除了T泛型外,还可以配置其他的方法,方便的调用;
OutputDeviceTraits类型继承DeviceTraits,我觉得不要功能也是可以实现的,后续直接typedef TypeConverter OutputDeviceConverter也可以实现,这么定义我觉得是为了代码易读,后期也方便扩展;比如audio_device_t其实有输入输出类型,不重新定义OutputDeviceTraits类型,易读性不佳且后续扩展不好;
最后一句就好理解了,模板调用;

以上完成后,还需要为mTable赋初值,可以按照我上面的例子赋初值,也可以用一种更好的方式,如下:

//这个宏定义可以理解为输入一个string参数,输出两个参数,一个是字符串string,另一个是string参数本身
#define MAKE_STRING_FROM_ENUM(string) { #string, string }
template <>
const OutputDeviceConverter::Table OutputDeviceConverter::mTable[] = {
    MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_NONE),
    MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
    MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
    ....

}

最后的最后,我们只需要使用OutputDeviceConverter::fromString()就可以完成对比查找功能了;如果后面又有新的配置项,我们怎么做呢?
像下面这样即可:

using OutputFlagTraits = DefaultTraits<audio_output_flags_t>;
typedef TypeConverter<OutputFlagTraits> OutputFlagConverter;

audio_output_flags_t是我们定义的基本枚举类型,OutputFlagConverter是最终成型可直接使用的类
是不是很简单,以后枚举对比就可以参考这个方案了!

本方案参考了Android系统的TypeConvert类,对它进行了一个小总结!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气好男人_Jack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值