수업에 대한 단일 책임 패턴은 얼마나 구체적이어야합니까?


14

예를 들어, 콘솔 게임 프로그램에 콘솔에 대한 모든 종류의 입력 / 출력 방법이 있다고 가정하십시오. 하나에 모두 유지하는 스마트겠습니까 inputOutput클래스 또는 같은보다 구체적인 클래스로 분해 startMenuIO, inGameIO, playerIO, gameBoardIO, 각 클래스 1-5 방법에 대해이 등 있도록?

같은 메모에서 그것들을 분류하는 것이 낫다면 IO네임 스페이스 에 배치하는 것이 현명 할 것입니다 IO.inGame.



관련 : 입력과 출력을 결합 할만한 좋은 이유를 본 적이 없습니다. 그리고 의도적으로 분리하면 코드가 훨씬 깨끗해집니다.
Mooing Duck

1
어쨌든 lowerCamelCase에서 어떤 언어로 수업을합니까?
user253751

답변:


7

업데이트 (복구)

다소 장황한 답변을 작성했기 때문에 다음과 같이 요약됩니다.

  • 네임 스페이스는 좋습니다. 의미가있을 때마다 사용하십시오.
  • 사용 inGameIOplayerIO클래스는 SRP의 위반으로 간주 될 수 있습니다. IO를 처리하는 방식을 응용 프로그램 논리와 결합하고 있음을 의미합니다.
  • 처리기 클래스에서 사용하거나 공유하는 몇 가지 일반 IO 클래스가 있습니다. 그런 다음 이러한 핸들러 클래스는 원시 입력을 애플리케이션 로직이 이해할 수있는 형식으로 변환합니다.
  • 출력도 마찬가지입니다. 이것은 상당히 일반적인 클래스로 수행 할 수 있지만 내부 게임 상태를 일반 IO 클래스가 처리 할 수있는 것으로 변환하는 핸들러 / 매퍼 객체를 통해 게임 상태를 전달합니다.

나는 당신이 이것을 잘못된 방식으로보고 있다고 생각합니다. 응용 프로그램의 구성 요소에 따라 IO를 분리하는 반면, 소스와 IO의 "유형" 에 따라 별도의 IO 클래스를 갖는 것이 더 합리적 입니다.

몇 가지 기본 / 일반 KeyboardIO클래스 MouseIO를 시작한 다음 필요한시기와 위치에 따라 해당 IO를 다르게 처리하는 서브 클래스가 있습니다.
예를 들어, 텍스트 입력은 게임 내 컨트롤과 다르게 처리하려는 것입니다. 각 유스 케이스에 따라 특정 키를 다르게 맵핑하려는 것을 알 수 있지만 맵핑은 IO 자체의 일부가 아니며 IO를 처리하는 방식입니다.

SRP를 고수하면서 키보드 IO에 사용할 수있는 몇 가지 클래스가 있습니다. 상황에 따라이 클래스와 다르게 상호 작용하고 싶을 것입니다. 그러나 유일한 역할은 사용자가 무엇을하고 있는지 알려주는 것입니다.

그런 다음이 객체를 처리기 객체에 삽입하여 원시 IO를 내 응용 프로그램 논리가 작동 할 수있는 대상에 매핑합니다 (예 : 사용자가 "w" 를 누르면 처리기가이를 매핑 함 MOVE_FORWARD).

이 핸들러는 차례로 문자를 움직이고 그에 따라 화면을 그리는 데 사용됩니다. 과도한 단순화, 그러나 그것의 요지는 이런 종류의 구조입니다.

[ IO.Keyboard.InGame ] // generic, if SoC and SRP are strongly adhered to, changing this component should be fairly easy to do
   ||
   ==> [ Controls.Keyboard.InGameMapper ]

[ Game.Engine ] <- Controls.Keyboard.InGameMapper
                <- IO.Screen
                <- ... all sorts of stuff here
    InGameMapper.move() //returns MOVE_FORWARD or something
      ||
      ==> 1. Game.updateStuff();//do all the things you need to do to move the character in the given direction
          2. Game.Screen.SetState(GameState); //translate the game state (inverse handler)
          3. IO.Screen.draw();//generate actual output

우리가 지금 가지고있는 것은 원시 형식의 키보드 IO를 담당하는 클래스입니다. 이 데이터를 게임 엔진이 실제로 이해할 수있는 것으로 변환하는 다른 클래스는이 데이터를 사용하여 관련된 모든 구성 요소의 상태를 업데이트하고 마지막으로 별도의 클래스가 출력을 화면으로 처리합니다.

모든 단일 클래스에는 단일 작업이 있습니다. 키보드 입력 처리는 입력이 처리하는 입력의 의미를 모르거나 관리 / 알아야하는 클래스에 의해 수행됩니다. 입력 (버퍼링, 버퍼링되지 않은 ...)을 얻는 방법 만 아는 것 입니다.

핸들러는이 정보를 나머지 응용 프로그램에서 내부 정보로 변환하여이 정보를 이해합니다.

게임 엔진은 번역 된 데이터를 가져와이를 사용하여 모든 관련 구성 요소에 문제가 있음을 알립니다. 이러한 각 구성 요소는 충돌 확인이든 문자 애니메이션 변경이든 상관없이 각 개별 개체에 따라 한 가지만 수행합니다.

그런 다음 이러한 객체는 상태를 다시 릴레이하고이 데이터는 Game.Screen본질적으로 역 IO 처리기로 전달됩니다. 내부 표현을 IO.Screen구성 요소가 실제 출력을 생성하는 데 사용할 수 있는 것으로 맵핑합니다 .


콘솔 응용 프로그램이므로 마우스가 없으며 메시지 또는 보드를 인쇄하면 입력과 밀접하게 연결됩니다. 귀하의 예에서 IOgame네임 스페이스 또는 클래스가 서브 클래스가 있습니까?
shinzou

@ kuhaku : 그들은 네임 스페이스입니다. 내가 말하는 것은 요점은, 응용 프로그램의 어떤 부분을 기반으로 서브 클래스를 만들면 기본 IO 기능을 응용 프로그램 논리와 효과적으로 밀접하게 결합한다는 것입니다. 애플리케이션의 기능에서 IO 담당하는 클래스가 생깁니다 . 그것은 나에게 SRP를 위반하는 것처럼 들린다. 이름 대 네임 스페이스 클래스와 관련하여 : 네임 스페이스를 95 % 선호하는 경향이 있습니다.
Elias Van Ootegem

내 답변을 요약하기 위해 내 답변을 업데이트했습니다
Elias Van Ootegem

예, 실제로 내가 가지고있는 또 다른 문제 (IO와 로직을 연결)는 실제로 입력과 출력을 분리하는 것이 좋습니다?
shinzou

@ kuhaku : 그것은 실제로 당신이하는 일과 입 / 출력이 얼마나 복잡한 지에 달려 있습니다. 처리기 (게임 상태와 원시 입력 / 출력 변환)가 너무 다른 경우 입력 및 출력 클래스를 분리해야합니다. 그렇지 않은 경우 단일 IO 클래스가 적합합니다.
Elias Van Ootegem

23

단일 책임 원칙은 이해하기 까다로울 수 있습니다. 내가 찾은 것은 문장을 쓰는 방식과 비슷하게 생각하는 것입니다. 많은 아이디어를 한 문장으로 만들려고하지 않습니다. 각 문장은 하나의 아이디어를 명확하게 설명하고 세부 사항을 연기해야합니다. 예를 들어 자동차를 정의하려면 다음과 같이 말하십시오.

내연 기관으로 구동되는 보통 4 개의 바퀴가 달린 도로 차량.

그런 다음 "차량", "도로", "바퀴"등을 개별적으로 정의합니다. 당신은 말하려고하지 않을 것입니다 :

차량 아래에 고정 된 차축에서 회전하고 생성되는 엔진에 의해 구동되는 4 개의 원형 물체를 갖는 여행을 가능하게하기 위해 포장되거나 달리 개선 된 2 개의 장소 사이에서 도로, 도로 또는 도로상의 사람들을 운송하기위한 차량 가솔린, 오일 또는 기타 연료를 공기로 연소시켜 동력을 공급합니다.

마찬가지로 클래스, 메소드 등을 중심 개념을 가능한 한 간단하게 설명하고 세부 사항을 다른 메소드 및 클래스에 지연 시키도록 노력해야합니다. 문장을 쓰는 것과 마찬가지로, 얼마나 큰 문장을 사용해야하는지에 대한 엄격한 규칙은 없습니다.


따라서 많은 단어 대신 몇 단어로 자동차를 정의하는 것과 같이 작지만 특정 클래스를 정의하는 것이 좋습니다?
shinzou

2
@kuhaku : 작습니다. 구체적입니다. 건조를 유지하는 한 비슷합니다. 디자인을 쉽게 변경하려고합니다. 작고 구체적인 것을 유지하면 어디에서 변경해야하는지 알 수 있습니다. 건조 상태를 유지하면 많은 장소를 변경하지 않아도됩니다.
본 카토

6
두 번째 문장은 "아빠, 선생님은이 페이지가 4 페이지 여야한다고 말씀하셨습니다.
corsiKa

2

가장 좋은 방법은 별도의 수업을 유지하는 것입니다. 소규모 수업은 나쁘지 않습니다. 사실 대부분의 경우 좋은 생각입니다.

특정 사례와 관련하여 분리 된 것을 사용하면 다른 처리기에 영향을주지 않고 특정 처리기의 논리를 변경하는 데 도움이 될 수 있으며 필요한 경우 새로운 입력 / 출력 방법을 추가하는 것이 더 쉬울 것이라고 생각합니다.


0

단일 책임 교장 은 수업을 변경할 이유가 하나만 있어야한다고 명시하고 있습니다. 수업에 여러 가지 이유가 있다면 다른 수업으로 나누고 작문을 활용하여이 문제를 해결할 수 있습니다.

당신의 질문에 대답하기 위해, 나는 당신에게 질문을해야합니다 : 당신의 수업은 변경해야 할 단 하나의 이유가 있습니까? 그렇지 않다면 각각 하나의 변경 이유가있을 때까지 더 전문화 된 클래스를 계속 추가하는 것을 두려워하지 마십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.