2013-03-23 2 views
1

나는처럼 보이는 DeviceSettingsManager 클래스가 있습니다표준 : :지도

class DeviceSettingsManager 
{ 
    int32_t PropertyA(); 
    void SetPropertyA(int32_t prop); 
    std::string PropertyB(); 
    void SetPropertyB(std::string prop); 

    // about 50 properties go here ... 
} 

을하고 내가 가지고있는 특성 문자열에 따라 속성을 설정해야합니다. 어떤 코드는 그렇게 보지 않는다 :

// Parse property string ("PropertyA = 100, PropertyB = xyz, ...") to key/value pairs 

if (key == "PropertyA") 
    manager.SetPropertyA(value); 
else if (key == "PropertyB") 
    manager.SetPropertyB(value); 

// 50 more properties ... 

를 잘 작성하지 아주 좋은가요?

setters_[key](value); // where for example key == "PropertyA" and value = 100 

그러나 문제가있다 :

첫 번째 아이디어는지도에서 세터를 저장하는 것입니다 나는지도 다른 펑터에 저장할 수 없습니다 : 물론

typedef boost::function<void(int32_t)> setter_int_t; 
typedef boost::function<void(std::string)> setter_string_t; 
std::map<std::string, ???> setters_; 

, I 두 개의지도를 가질 수 있습니다 (int32_tstd::string). 그러나 그것은 잘 확장되지 않습니다. float 또는 double 또는 심지어 user_defined_class과 같은 인자 유형을 가진 새로운 setter를 추가해야한다면 더 많은지도가 필요합니다.

다른 방법은 을 사용하는 것입니다. boost::function에 다시 reinterpret_cast이 필요합니다. 다시 문제가 발생합니다.

질문 : 수십억의 if-else 문을 작성하지 못하도록 이러한 PropertyManagers를 어떻게 관리 할 수 ​​있습니까?

답변

0

지도를 만들면 <key, parser>일까요? 그리고 초기 문자열, 위치 및 관리자 객체를 파서에 전달합니다. 맵의 묶음보다 융통성이 있지만 여전히 구체적인 파서로 맵을 채워야합니다.

1

마지막으로, 방법은 어떻게 (이 최고의 하나인지 모른다) :

// checks (map.find(...)) omitted for brevity 

struct base_type_holder 
{ 
    virtual ~base_type_holder() {}; 
}; 

template<typename T> 
struct type_holder : base_type_holder 
{ 
    typedef T type; 
}; 

std::map<std::string, boost::shared_ptr<base_type_holder> > types_; 

template<typename T> 
void RegisterSetterType(const std::string& name) 
{ 
    types_[name].reset(new type_holder<T>); 
} 

boost::shared_ptr<base_type_holder> GetSetterType(const std::string& name) 
{ 
    return types_[name]; 
} 

template<typename T> 
std::map<std::string, boost::function<void(T)> >& SettersMap() 
{ 
    static std::map<std::string, boost::function<void(T)> > settersMap; 
    return settersMap; 
} 

template<typename T, typename H> 
void AddSetter(const std::string& name, void (H::*Setter)(T)) 
{ 
    static H settingsManager; 
    RegisterSetterType<T>(name); 

    SettersMap<T>()[name] = boost::bind(Setter, &settingsManager, ::_1); 
} 

void CallSetter(const std::string& name, const std::string& value) 
{ 
    boost::shared_ptr<base_type_holder> base_type = GetSetterType(name); 
    if (dynamic_cast<type_holder<int32_t> *>(base_type.get())) 
    { 
     SettersMap<int32_t>()[name](atoi(value.c_str())); 
    } 
    else if (dynamic_cast<type_holder<std::string> *>(base_type.get())) 
    { 
     SettersMap<std::string>()[name](value); 
    } 
} 

// Now somewhere in .cpp 
AddSetter<int32_t, DeviceSettingsManager>("PropertyA", &DeviceSettingsManager::SetPropertyA); 
AddSetter<const std::string&, DeviceSettingsManager>("PropertyB", &DeviceSettingsManager::SetPropertyB); 

// other... 

// later 
CallSetter(key, value); // key = "PropertyA", value = "100"