2012-02-19 2 views
2

내 C++ 클래스 디자인에 대한 질문이 있습니다. 종종 나는 이와 같은 작은 문제에 직면 해 있으며 더 잘 받아 들여지는 것에 관해서 조언을 원합니다.기본 C++ 디자인

UDP를 통해 일부 장치의 온도를 모니터링하는 클래스가 있습니다. 장치가 데이터 패킷을 수신하면, "x \ n"을 stdout에 인쇄하여 수신되었음을 나타냅니다. 그런 다음 해당 패킷의 데이터를 확인하고 데이터가 장치의 온도가 너무 높음을 표시하지 않는지 확인하십시오. 너무 높으면 몇 가지 기능을 호출해야합니다. 그렇지 않으면 다른 기능을 호출해야합니다.

enum temperature {TEMPERATURE_FINE, TEMPERATURE_EXCEEDED}; 

int main(int argc, char* argv[]) 
{ 
    std::vector<std::string> args(argv+1, argv + argc); 

    if(!args.size()) 
     cout << "No parameters entered.\n"; 
    else 
    { 
     CTemperatureMonitor tempMonitor(args); 

     if(tempMonitor.MonitorTemperature() == TEMPERATURE_EXCEEDED) 
      tempMonitor.ActivateAlarm(); 
     else 
      tempMonitor.DisableAlarm(); 
    } 

    return 0; 
} 

tempMonitor.MonitorTemperature은() std::cout << "x\n"를 호출 여기서 나는이 작업을 수행해야하는 경우

는 잘 모르겠어요. 따라서 std::cout << "x\n"이 클래스에 내장되어 있습니다.

또는 : std::cout << "x\n"이 클래스에 포함되지 않습니다

enum temperature {TEMPERATURE_FINE, TEMPERATURE_EXCEEDED}; 

int main(int argc, char* argv[]) 
{ 
    std::vector<std::string> args(argv+1, argv + argc); 

    if(!args.size()) 
     cout << "No parameters entered.\n"; 
    else 
    { 
     CTemperatureMonitor tempMonitor(args); 

     temperature tempExceeded = tempMonitor.MonitorTemperature(); 
     std::cout << "x\n"; 
     if(tempExceeded == TEMPERATURE_EXCEEDED) 
      tempMonitor.ActivateAlarm(); 
     else 
      tempMonitor.DisableAlarm(); 
    } 

    return 0; 
} 

.

CTemperatureMonitor::ActivateAlarm()CTemperatureMonitor::DisableAlarm()을 호출하기 전에 std::cout << "x\n"이 발생해야합니다.

나는 이것이 사소하고 단순한 것처럼 보일 수도 있지만, 정확히 어떤 것이 정확하게 클래스의 일부인지 궁금해합니다. 클래스가 표준 출력으로 출력해야합니까? 내가 다른 것과 상관없이 어떤 변화를 가져올 수 있습니까? 나는 이것에 대해 솔직하게 말하고 있는가?

또한 제쳐두고 전역 변수는 잘못된 실행으로 간주됩니다. 메인과 클래스 모두에서 온도 열거 형을 사용합니다. CTemperatureMonitor 클래스에서 한 번, 한 번 또는 두 번 전역 적으로 선언해야합니까? 이 질문은 다소 구체적으로 보일지라도 실제로는 나를 위해 훨씬 더 많은 것을 정리할 것입니다.

감사합니다.

+1

단일 책임, 최소한의 결합, 모듈성 및 재사용 가능성에 대해 생각해보십시오. –

+0

나를 위해 그것은 'x'가있는 줄이 무엇인지에 달려 있습니다. 온도의 상태와 관련이 있다면 CTemperatureMonitor 클래스에있을 것입니다. 그것이 다른 것들을위한 부분 일 뿐이라면 나는 그것을 수업 외부에 두었습니다. –

+0

그냥 "나는 패킷을 받았습니다"라고 말합니다. 아무것도 더, 아무것도 덜. –

답변

1

먼저 다양한 크기의 프로젝트가 있으며 그 크기에 따라 다릅니다. (그리고 비평), 조언은 실제로 다를 것입니다. 그래서 처음으로 경험적 규칙 :

"Logger", "Option Parser"등의 "프레임 워크"의 크기는 전체 프로그램의 10 %를 넘지 않아야합니다. 이 시점이 지나면 과장 될뿐입니다. 운동의 목표가 아니라면!

그렇다면 실제 질문을 볼 수 있습니다. 제쳐두고, 내가 전역 변수를 알고


또한, 가난한 연습으로 간주됩니다. 메인과 클래스 모두에서 온도 열거 형을 사용합니다. CTemperatureMonitor 클래스에서 한 번, 한 번 또는 두 번 전역 적으로 선언해야합니까?

당신은 실제로 변수유형 여기 착각하고 있습니다. 온도은 유형 (열거 형)입니다.

일반적으로 유형은 프로그램의 다양한 부분 사이의 다리 역할을하기 때문에 모든 부품이 동일한 유형 정의를 공유하는 것이 중요합니다. 따라서 형식에 대해서는 실제로 두 번 선언하는 것이 좋지 않습니다.

또한 모든 글로벌 변수가 악의적이지는 않습니다. 글로벌 변수은 (공유 상태)이지만 글로벌 상수는이며 일반적으로 유형과 비슷한 역할을합니다.


나는이 정말 사소한하고 단순한 보일 수 있습니다 알고 있지만, 나는 종종 정확하게 클래스의 일부가되어야 무엇인지 궁금하네요. 클래스가 표준 출력으로 출력해야합니까? 내가 다른 것과 상관없이 어떤 변화를 가져올 수 있습니까? 나는 이것에 대해 솔직하게 말하고 있는가?

출력 두 가지 종류가 있습니다

  • 프로그램이 무엇 이다 그들이
  • 실제 출력
  • 가 발생하는 경우 문제를 진단하는 데 사용되는 로그 출력,

프로그램에 따라 둘 다 또는 아닐 수도 있습니다.

보잘것없는 관점에서 볼 때 일반적으로 혼합하지 않는 것이 좋습니다. 예를 들어, 로깅을 파일에 완벽하게 전송할 수 있으며, 심각 할 때는 stderr을 사용하고, "유용한"항목에는 stdout을 사용하십시오.

실제로 출력을 위해 하나씩 두 개의 싱크가 필요하기 때문에 실제로 디자인이 다소 구동됩니다.

매우 단순한 프로그램이므로 가장 간단한 방법은 두 개의 다른 std::ostream&을 생성시 클래스에 전달하는 것입니다. 아니면, 더 간단하게, 두 가지 일반적인 함수를 가지고 있고 (악의적 인) 전역 변수를 사용하십시오.

큰 프로그램에서는 다양한 로그 수준을 갖는 Logger 클래스를 설계하고 로그 라인의 함수 이름, 파일 이름 및 행 번호를 (자동으로) 등록하는 특정 매크로를 제공 할 수 있습니다. 또한 릴리스 빌드에서 로깅 DEBUG/DEV 로깅을 사용하지 않도록 설정할 수있는 간단한 로깅 메커니즘이 있습니다.

+0

답변 해 주셔서 감사합니다. 유익한 정보입니다. 내 프로그램에는 로깅 형식이 없습니다. cout << "x \ n"은 실제 출력입니다. 나는 그것이 이상하게 보일 수도 있음을 안다. 그래서 주어진 결과는 오직 하나 뿐이며, 그것은 실제적이며 항상 stdout이어야한다. –

+0

@ user968243 : 나는 그것을 overenginner하지 않는 것이 좋습니다. 'std :: cout'은 당장 작동하므로 그냥 그대로 두십시오. 언젠가 당신이 언젠가 파일에 로그인하기를 원할지라도, 출력물을 리다이렉트 할 수 있습니다. (또한 파일과 콘솔에 모두 로그인 할 때'tie '를 사용하십시오.) 추가 기능 (예 : 활성화/비활성화 할 수있는 로깅 수준)을 원할 경우에만 로거 클래스를 도입하고 * 그 순간에는 * 응용 프로그램을 리팩토링하십시오. –

1

The single level of abstraction principle은 높은 수준에서 일부를 수행하고 낮은 수준에서 추상화하는 대신 동일한 방법으로 모든 I/O를 수행하는 것이 좋습니다.

다른 말로하면, 그 원리를 믿는다면, 일부를 숨기고 숨기는 대신에 동일한 방법으로 cin/cout을 통해 입력과 출력을 유지하는 것이 좋습니다. 그것은 각 클래스에서 더 적은 의존성을 가진 더 읽기 쉬운 코드를 제공하는 경향이 있습니다.

1

Single responsibility principle에 따르면 두 번째 옵션이 선호됩니다 (모든 클래스는 정확히 하나의 책임을 가져야하며 결과를 출력하지 않고 케이스의 온도를 모니터링해야합니다). 다른 클래스를 설정하여 온도 모니터링 결과 (예 : 특정 로그 파일 또는 결과에 결과를 기록)

+0

선을 그리기가 어렵습니다. 예를 들어 온도를 모니터링하는 일 중 일부는 std :: cout << "x \ n"; 말하자면 실제로 온도를 모니터링하고 있습니다. –

+0

물론 실제 시스템 설계에 대해 이야기하고 있습니다. 질문은 일반적으로 온도 모니터링이 예제 일 뿐이므로 디버그 로깅 문제는 고려하지 않았습니다.). –

+0

그래, 나는 선을 그어야 할 곳을 결정할 때, 어떤 것이 수업에 없어야한다고 결정할 때 어려워진다. 확실한 회색 영역이있는 것 같습니다! –

0

제 생각에는 그런 경우에는 클래스에 cout을 포함하면 안됩니다. 때로는 나중에 파일로 출력하거나 출력하지 않아도됩니다. 따라서 cout이 클래스에 추가되지 않으면 변경하지 않고 클래스 코드를 재사용 할 수 있습니다.

1

프로그램에 대한 정보를 기록하는 방법은 정상입니다.
이 방법이 글로벌 일 수도 있습니다.

그렇지 않으면 메소드를 호출 할 때 너무 복잡해집니다.
개선 할 수있는 유일한 방법은 다음과 같습니다.

출력 스트림을 사용자가 선택하는대로 설정할 수있는 로거 클래스가 있습니다 (또는 기존 스트림을 사용합니다) (std :: out과 아무것도 인쇄하지 않습니다).
궁극적으로 릴리스 모드에서 실행되는 코드의 속도를 늦추지 않도록 #define 뒤에 숨겨져있는 로거가 있어야합니다.

0

아니요. main의 책임은 명령 행 인수로 응용 프로그램을 시작하고 리턴 값을 제공하는 것입니다. 그 밖의 모든 것은 존재해서는 안됩니다. "개체 디자인, 역할, 책임 및 공동 작업"과 같은 책을 살펴볼 수도 있습니다.