2016-06-14 5 views
0

내가 코드의 반복되는 블록이 있다고 가정 (nondet 공장.?) : 분명히디자인 패턴

Class1 c1; 
try { 
    c1.parse(x); 
} catch(Exception& e) { 
    Class2 c2; 
    try { 
     c2.parse(x); 
    } catch(Exception& e) { 
     Class3 c3; 
     try { 
      // ... 
     } 
     // ... 
    } 
} 

, 내가 관심이 누구인지는 # = (1,2,3 첫 Class#입니다 , ...) parse가 예외를 throw하지 않는 인스턴스.

선택적으로 Class1, ..., ClassN에는 공통 수퍼 클래스가 있으므로이를 반환 유형으로 사용할 수 있습니다.

간결한 코드이 작업을 추상화하는 방법은 무엇입니까? 코드에서 여러 번 반복 될 것이라고 생각하십니까?

STL을 사용하고 있기 때문에 프로젝트 요구 사항, C++ (11)를 사용하는 행위는 허용되지 않습니다 향상 :( 매크로 회색 영역입니다습니다.

+0

나는 당신이 무엇을 요구하고 있는지 명확하지 않습니다. 보다 간결한 예제를 줄 수 있습니까? 당신은 단지 당신이 programm에있는 어떤 타입으로 메시지를 deserialize하려고 시도함으로써 실제 직렬화 된 타입을 찾으려고 하는가? 그것은 매우 나쁜 디자인입니다. 그것이 다른 것이라면 명확히하십시오. – SergeyA

+4

정상적인 제어 흐름에 대한 예외 처리를 남용하고 있습니다. 대신에'ClassX'에 상태를주고 'bool'으로 변환하여 성공을 확인하면 쉽게 해결할 수 있습니다. – nwp

+0

@ SergeyA, 네가 옳은 것 같아. 입력은 XML DOM이며 클래스 계층 구조에 맞게 파싱하거나 예외를 throw하려고합니다. 이 특정 측면은 구문 분석이 모호 할 수 있으며 많은 가능한 클래스로 XML 요소를 구문 분석해야합니다. – fferri

답변

1

같은 방법 및 제한 나중에 편리하게 표현할 수 있도록 앞쪽에 자리 잡은 뒤 :

#include <string> 
#include <stdexcept> 

struct Class1 { void parse(const std::string&); }; 
struct Class2 { void parse(const std::string&); }; 
struct Class3 { void parse(const std::string&); }; 

struct none_type {}; 

template<class C> 
    struct try_impl 
    { 
    try_impl(int index) 
     : _index(index) 
     { 
     } 
    void apply(int& which, C& c, const std::string& s) const 
    { 
     if (which >= 0) 
     return; 
     try { 
     c.parse(s); 
     which = _index; 
     } 
     catch(...) { 
     // logging here? 
     } 
    } 

    int _index; 
    }; 

template<> 
    struct try_impl<none_type> 
    { 
    try_impl(int index) 
     : _index(index) 
     { 
     } 
    void apply(int& which, none_type& c, const std::string& s) const 
    { 
    } 

    int _index; 
    }; 

// attempt to parse all given objects. Return the index of the first one that 
// passed 
// return -1 if non parse correctly 
// 
template<class C1, class C2 = none_type, class C3 = none_type, class C4 = none_type, class C5 = none_type> 
struct parse_attempt_impl 
{ 
    static int apply(const std::string& s,C1 c1, C2 c2 = C2(), C3 c3 = C3(), C4 c4 = C4(), C5 c5 = C5()) 
{ 
    int which = -1; 
    try_impl<C1>(0).apply(which, c1, s); 
    try_impl<C2>(1).apply(which, c2, s); 
    try_impl<C3>(2).apply(which, c3, s); 
    try_impl<C4>(3).apply(which, c4, s); 
    try_impl<C5>(4).apply(which, c5, s); 
    return which; 
} 
}; 

// you will need to make as many of these as you need 
template<class C1, class C2, class C3> 
int parse_attempt(const std::string& s, C1 c1, C2 c2, C3 c3) 
{ 
    return parse_attempt_impl<C1, C2, C3>::apply(s, c1, c2, c3); 
} 

template<class C1, class C2, class C3, class C4> 
int parse_attempt(const std::string& s, C1 c1, C2 c2, C3 c3, C4 c4) 
{ 
    return parse_attempt_impl<C1, C2, C3, C4>::apply(s, c1, c2, c3, c4); 
} 



int main(int argc, char**argv) 
{ 
    std::string x(argv[1]); 
    int which = parse_attempt(x, Class1(), Class2(), Class3()); 
} 
0

당신은

같은 인터페이스와 공장 같은 방법을 가질 수 있습니다 종기를 많이 - ++ 03 c를 우리가 그것을 부스트 라이브러리가 그것을 할 방법을 할 수밖에에
ParserPtr CreateParser(unsinged level) 
{ 
    switch(level) 
    { 
     case 0: 
      return ParserPtr(new Class0); 
     //... 
    } 
    return nullptr; 
} 

및 재 작성하여 variadics없이

void Parse() 
{ 
    unsined errorLevel = 0; 
    while(auto p = CreateParser(errorLevel)) 
    { 
     try 
     { 
      p->parse(); /*...*/ 
      //deallocate if ParserPtr is not shared_ptr or other smart ptr 
      return; 
     } 
     catch(Exception & e) 
     { 
      ++errorLevel; 
      /*Extra exception handling, deallocating p if needed*/ 
     } 
    } 
    //Handle case, when no parser succeeded 
} 
1

이렇게하지 마십시오. 아프다. std :: optional (즉, 클래스 T : static std :: optional Create (...))을 반환하는 '명명 된 생성자'를 사용하고 내부 생성자를 private/protected로 만듭니다. 좋습니다, 정말로 (또는 라이브러리를 사용하면 변경할 수 없습니다) :

#include <iostream> 
#include <string> 

struct ParseReturn {}; 

template<int i> 
struct Parser 
{ 
    ParseReturn parse(const std::string&) 
    { 
     return ParseReturn(); 
    } 
}; 

template<typename P, typename... Args> 
class ParseFirst 
{ 
public: 
    static ParseReturn parse(const std::string& s) 
    { 
     try 
     { 
      return P().parse(s); 
     } 
     catch(...) 
     { 
      return ParseFirst<Args...>::parse(s); 
     } 
    } 
}; 

template<typename P> 
class ParseFirst<P> 
{ 
public: 
    static ParseReturn parse(const std::string& s) 
    { 
     try 
     { 
      return P().parse(s); 
     } 
     catch(...) 
     { 
      // re-throw maybe? 
     } 
    } 
}; 

int main() { 
    std::string s; 
    ParseFirst< Parser<1>, Parser<2> >::parse(s); 
    return 0; 
} 
+0

OP는 C++ 11이 허용되지 않는다고 말했기 때문에 다양한 템플릿을 배제했습니다. –