"MVC"의 "컨트롤러"는 무엇입니까?


186

MVC의 기본 개념을 이해한다고 생각합니다. 모델에는 응용 프로그램의 데이터와 동작이 포함되어 있으며보기는 사용자에게 표시하고 컨트롤러는 사용자 입력을 처리합니다. 내가 불확실 해요 것은 정확히 무엇인지 컨트롤러에 간다.

예를 들어 상당히 간단한 응용 프로그램이 있다고 가정 해 보겠습니다 (특히 Java를 생각하고 있지만 다른 원칙과 동일한 원칙이 적용된다고 가정합니다). 코드를 app.model, app.view및 이라는 3 개의 패키지로 구성 app.controller합니다.

app.model패키지, 나는 응용 프로그램의 실제 행동을 반영하는 몇 가지 클래스가 있습니다. 이들을 extends Observable사용 setChanged()하고 notifyObservers()적절한 경우보기를 업데이트하여보기를 트리거합니다.

app.view패키지는 사용하는 클래스 (또는 디스플레이의 다른 유형에 대한 여러 클래스)가 javax.swing디스플레이를 처리하기 위해 구성 요소를. 이러한 구성 요소 중 일부는 모델로 피드백해야합니다. 올바르게 이해하면 View는 피드백과 관련이 없어야합니다. 피드백은 컨트롤러가 처리해야합니다.

그렇다면 실제로 컨트롤러에 무엇을 넣습니까? public void actionPerformed(ActionEvent e)컨트롤러의 메소드를 호출하여 View에 뷰를 넣 습니까? 그렇다면 컨트롤러에서 유효성 검사 등을 수행해야합니까? 그렇다면 오류 메시지를 다시보기로 피드백하는 방법-모델을 다시 통과해야합니까, 아니면 컨트롤러가 다시보기로 다시 보내야합니까?

확인이 View에서 수행되면 Controller에 무엇을 넣습니까?

긴 질문에 대해 유감스럽게 생각합니다. 프로세스에 대한 이해를 문서화하고 싶었고 누군가 가이 문제를 분명히 밝힐 수 있기를 바랍니다.

답변:


520

당신이 제안한 예에서, 당신은 맞습니다 : 인터페이스에서 "사용자가 '이 항목 삭제'버튼을 클릭했습니다"는 기본적으로 컨트롤러의 "삭제"기능을 호출해야합니다. 그러나 컨트롤러는보기의 모양을 모릅니다. 따라서 "어떤 항목을 클릭 했습니까?"와 같은 정보를 수집해야합니다.

대화 형태로 :

보기 : "이봐, 컨트롤러, 사용자가 방금 항목 4를 삭제하고 싶다고 말 했어요."
컨트롤러 : "음, 자신의 자격 증명을 확인한 후, 그는 그렇게 할 수 있습니다 ... 이봐, 모델, 나는 당신이 항목 4를 얻고 그것을 삭제하기 위해 무엇이든하길 원합니다."
모델 : "항목 4 ... 가져 왔습니다. 삭제되었습니다. 컨트롤러로 돌아갑니다."
Controller : "여기, 새로운 데이터 세트를 수집하겠습니다.
보기 : "멋지네요, 이제 새 세트를 사용자에게 보여 드리겠습니다."

이 섹션의 끝에는 옵션이 있습니다.보기에서 별도의 요청을 수행하여 "가장 최근 데이터 세트를 제공"하여 더 순수하거나 컨트롤러가 "삭제를 사용하여 새 데이터 세트를 암시 적으로 반환합니다. "작업.


90
이 대화는 내가 만난 MVC에 대한 최고의 설명입니다. 감사합니다!
Paul Walker

13
모두 괜찮지 만 모델에서 직접 읽는 뷰에는 아무런 문제가 없습니다 . "컨트롤러는 데이터 정책이 아닙니다". 컨트롤러를 얇게 유지하라는 교리도 있습니다. 뷰 헬퍼는 뷰에서 사용할 준비가 된 데이터를 수집하기에 완벽한 장소입니다. 일부 데이터 액세스 로직을 재사용하기 위해 전체 컨트롤러 스택을 디스패치 할 필요는 없습니다. 자세한 내용 : rmauger.co.uk/2009/03/…
예외 e

1
"예외 e"에 동의합니다. 모델의 데이터는 반드시 컨트롤러 일 필요는없는 많은 이벤트에 의해 업데이트 될 수 있으므로 일부 MVC 설계에서 M은 V에 데이터가 더럽다는 신호를 보내고 V는 자체적으로 새로 고칠 수 있습니다. 이 경우 C는 역할을 수행하지 않습니다.
Mishax

68

문제 MVC는 사람들이 뷰, 컨트롤러 및 모델이 가능한 한 독립적이어야한다고 생각한다는 것입니다. 그것들은 뷰가 아니며 컨트롤러가 종종 얽혀 있다고 생각합니다 M(VC).

컨트롤러는 사용자 인터페이스의 입력 메커니즘으로, 특히 GUI와 함께보기에서 종종 엉켜 있습니다. 그럼에도 불구하고 뷰가 출력되고 컨트롤러가 입력됩니다. 뷰는 종종 해당 컨트롤러없이 작동 할 수 있지만 일반적으로 뷰가 없으면 컨트롤러의 유용성이 훨씬 떨어집니다. 사용자 친화적 인 컨트롤러는 뷰를 사용하여보다 의미 있고 직관적 인 방식으로 사용자 입력을 해석합니다. 이것이 컨트롤러 개념을보기에서 분리하기 어렵게 만드는 것입니다.

밀폐 된 상자의 감지 영역에서 무선 제어 로봇을 모델로 생각하십시오.

모델은 출력 (디스플레이) 개념이없는 상태 및 상태 전이에 관한 것입니다. 현장에서 로봇의 위치를 ​​파악할 수 있고 로봇은 위치를 전환하는 방법을 알고 있습니다 (앞으로 / 뒤로 / 왼쪽 / 오른쪽으로 이동합니다.보기 나 컨트롤러없이 쉽게 구상 할 수 있지만 유용한 것은 없습니다.

컨트롤러가없는보기, 예를 들어 스크롤 콘솔 아래로 스트리밍하는 (x, y) 좌표로 로봇 위치를보고있는 다른 방에있는 네트워크의 다른 방에있는 누군가를 생각하십시오. 이 뷰는 모델의 상태 만 표시하지만이 녀석에는 컨트롤러가 없습니다. 컨트롤러없이이보기를 쉽게 구상 할 수 있습니다.

예를 들어 무선 주파수 컨트롤러가 로봇의 주파수에 맞춰진 벽장에 잠겨있는 사람이 보이지 않는 컨트롤러를 생각해보십시오. 이 컨트롤러는 입력을 보내고 있으며 모델에 수행중인 작업을 모를 경우 상태 전환을 유발합니다 (있는 경우). 구상하기는 쉽지만보기에서 일종의 피드백 없이는 실제로 유용하지 않습니다.

가장 사용자 친화적 인 UI는 컨트롤러와 뷰를 조정하여보다 직관적 인 사용자 인터페이스를 제공합니다. 예를 들어 로봇의 현재 위치를 2D로 표시하는 터치 스크린이있는 뷰 / 컨트롤러가 사용자가 로봇의 바로 앞에있는 지점을 터치 할 수 있다고 상상해보십시오. 컨트롤러는 뷰포트의 위치 및 스케일, 화면상의 로봇의 픽셀 위치에 대해 터치 된 스팟의 픽셀 위치 등 뷰에 대한 세부 정보가 필요합니다. 라디오 컨트롤러).

아직 질문에 대답 했습니까? :-)

컨트롤러는 모델이 상태를 전환하는 데 사용되는 사용자의 입력을받는 것입니다. 뷰와 컨트롤러를 분리 된 상태로 유지하려고하지만 서로 상호 의존적 인 경우가 많으므로 경계가 모호한 경우 괜찮습니다. 예를 들어 별도의 패키지로 뷰와 컨트롤러를 깔끔하게 분리하지 못할 수 있습니다. 좋아하지만 괜찮습니다. 뷰가 모델과 다르기 때문에 컨트롤러가 뷰와 완전히 분리되지 않을 수도 있습니다.

... 컨트롤러에서 유효성 검사 등을 수행해야합니까? 그렇다면 오류 메시지를 다시보기로 피드백하는 방법-모델을 다시 통과해야합니까, 아니면 컨트롤러가 다시보기로 다시 보내야합니까?

확인이 View에서 수행되면 Controller에 무엇을 넣습니까?

링크 된 뷰와 컨트롤러는 모델을 거치지 않고 자유롭게 상호 작용해야한다고 말합니다. 컨트롤러는 사용자의 입력을 받아 유효성 검사를 수행해야하지만 (아마도 모델 및 / 또는보기의 정보를 사용하여) 유효성 검사에 실패하면 컨트롤러가 관련보기를 직접 업데이트 할 수 있어야합니다 (예 : 오류 메시지).

이것에 대한 산성 테스트는 독립적 인 견해 (예 : 네트워크를 통해 로봇 위치를보고있는 다른 방의 사람)가 다른 사람의 유효성 검사 오류 (예 : 옷장에있는 사람)의 결과로 볼 수 있는지 여부입니다 로봇에게 현장에서 물러나라고 지시했습니다. 일반적으로 대답은 아니오입니다. 유효성 검사 오류로 인해 상태 전이가 방지되었습니다. 상태 추적이없는 경우 (로봇이 이동하지 않은 경우) 다른 견해를 말할 필요가 없습니다. 옷장에있는 사람은 단지 잘못된 전환 (보기가 안 됨-잘못된 사용자 인터페이스)을 유발하려고 시도한 피드백을 얻지 못했으며 아무도 그 사실을 알 필요가 없습니다.

터치 스크린을 가진 사람이 로봇을 현장 밖으로 보내려고한다면, 로봇을 감지 구역 밖으로 보내 로봇을 죽이지 말라고하는 사용자에게 친근한 메시지를 받았지만, 아무도 이것을 알 필요가 없습니다.

다른 뷰 이러한 오류에 대해 알아야 할 경우 사용자의 입력과 결과 오류가 모델의 일부이며 전체가 조금 더 복잡 하다는 것을 효과적으로 말하고 있습니다 ...


23

다음은 MVC의 기본 사항에 대한 좋은 기사 입니다.

그것은 ...

컨트롤러-컨트롤러는 뷰와의 상호 작용을 모델에서 수행 할 동작으로 변환합니다.

다시 말해 비즈니스 로직입니다. 컨트롤러는보기에서 사용자가 수행 한 작업에 응답하고 응답합니다. 유효성 검사를 여기에두고 유효성 검사에 실패하거나 성공하면 적절한보기를 선택합니다 (오류 페이지, 메시지 상자 등).

Fowler 에는 또 다른 좋은 기사가 있습니다.


MVP는 참조하는 기사에서 논의 된 또 다른 옵션입니다. martinfowler.com/eaaDev/ModelViewPresenter.html
Jon

링크를 주셔서 감사합니다, 그들은 확실히 흥미로운 독서를합니다.
Paul Walker

18

MVC 패턴은 단순히 프레젠테이션 (=보기) 과 비즈니스 로직 (= 모델) 을 분리 하기를 원합니다 . 컨트롤러 부분은 혼동을 일으킬 수 있습니다.


1
정확히, 내가 지금까지 항상 생각했지만 결코 다른 사람에게 말할 용기가 없었습니다.… 또는 올바른 단어를 찾지 못할 수도 있습니다.
user1451111

1
Model-View-Confusion
비가 오는

10

실제로 컨트롤러 개념이 특히 유용한 개념을 찾지 못했습니다. 코드에서 엄격한 모델 / 뷰 분리를 사용하지만 명확하게 정의 된 컨트롤러는 없습니다. 불필요한 추상화 인 것 같습니다.

개인적으로 본격적인 MVC는 혼란스럽고 지나치게 복잡한 디자인으로 쉽게 이어진다는 점에서 팩토리 디자인 패턴처럼 보입니다. 건축 우주 비행사가 되지 마십시오 .


9

귀하의 질문에 근거하여 모델의 역할에 약간 헷갈리는 느낌이 들었습니다. 모델은 응용 프로그램과 관련된 데이터에 고정됩니다. 앱에 데이터베이스가있는 경우 모델의 작업은 데이터베이스와 대화하는 것입니다. 또한 해당 데이터와 관련된 간단한 논리도 처리합니다. TABLE.foo == "Hooray!"인 모든 경우에 대해 말하는 규칙이있는 경우 그리고 TABLE.bar == "휴가!" 그런 다음 TABLE.field = "W00t!"를 설정하면 모델에서 처리하게됩니다.

컨트롤러는 대부분의 응용 프로그램 동작을 처리해야합니다. 따라서 귀하의 질문에 대답하십시오 :

Controller의 메소드를 호출하여 공용 void actionPerformed (ActionEvent e)를 View에 넣습니까?

나는 아니오라고 말할 것입니다. 나는 그것이 컨트롤러에 살아야한다고 말하고 싶습니다. View는 단순히 사용자 인터페이스에서 오는 데이터를 Controller에 공급하고 Controller가 응답 할 호출 할 메소드를 결정하게합니다.

그렇다면 컨트롤러에서 유효성 검사 등을 수행해야합니까?

검증의 대부분은 실제로 Controller에 의해 수행되어야합니다. 데이터가 유효한지 여부에 대한 질문에 답해야하며, 유효하지 않은 경우 적절한 오류 메시지를 View에 제공하십시오. 실제로, 사용자 환경을 개선하기 위해 간단한 온 전성 검사를보기 계층에 통합 할 수 있습니다. (주로 웹 환경을 생각하고 있습니다. 사용자가 전체 제출-> 프로세스->로드 페이지주기를 기다리지 않고 사용자가 "제출"을 누르는 순간 오류 메시지가 표시되도록 할 수 있습니다. .) 조심해; 당신은 필요 이상으로 노력을 복제하고 싶지 않으며 많은 환경에서 (웹을 생각하고 있습니다) 사용자 인터페이스에서 오는 모든 데이터를 불결한 더러운 팩으로 취급 해야하는 경우가 종종 있습니다 당신이 할 때까지 거짓말

그렇다면 오류 메시지를 다시보기로 피드백하는 방법-모델을 다시 통과해야합니까, 아니면 컨트롤러가 다시보기로 다시 보내야합니까?

Controller가 알려줄 때까지 View가 다음에 어떤 일이 발생하는지 알 필요가없는 프로토콜을 설정해야합니다. 사용자가 해당 버튼을 after 후 어떤 화면이 표시됩니까? View는 알 수 없으며 Controller는 방금 얻은 데이터를 볼 때까지 알 수 없습니다. "예상 한대로이 다른 화면으로 이동"또는 "이 화면을 그대로 유지하고이 오류 메시지를 표시하십시오"일 수 있습니다.

내 경험상 모델과 뷰 사이의 직접적인 통신은 매우 제한적이어야하며 뷰는 모델의 데이터를 직접 변경해서는 안됩니다. 컨트롤러의 작업이어야합니다.

확인이 View에서 수행되면 Controller에 무엇을 넣습니까?

위 참조; 실제 검증은 컨트롤러에 있어야합니다. 그리고 지금까지 컨트롤러에 무엇을 넣을 지에 대한 아이디어가 있기를 바랍니다. :-)

가장자리에서 약간 흐릿해질 수 있습니다. 소프트웨어 엔지니어링만큼 복잡한 모든 것들과 마찬가지로 판결 요청도 풍부 할 것입니다. 최선의 판단을하고이 앱 내에서 일관성을 유지하고 배운 교훈을 다음 프로젝트에 적용하십시오.


7

컨트롤러는 실제로 View의 일부입니다. 요청을 수행하는 데 필요한 서비스를 파악하고,보기에서 값을 서비스 인터페이스에 필요한 오브젝트로 비 정렬 화하고, 다음보기를 판별하고, 다음보기가 사용할 수있는 양식으로 응답을 마샬링하는 것이 목적입니다. . 또한 발생 된 예외를 처리하고 사용자가 이해할 수있는보기로 렌더링합니다.

서비스 계층은 사용 사례, 작업 단위 및 모델 객체를 알고있는 것입니다. 컨트롤러는보기 유형마다 다릅니다. 데스크톱, 브라우저 기반, Flex 또는 모바일 UI에 동일한 컨트롤러가 없습니다. 저는 이것이 실제로 UI의 일부라고 말합니다.

서비스 지향 : 작업이 완료되는 곳입니다.


3

컨트롤러는 기본적으로 뷰와 모델 간의 조정을위한 것입니다.

불행히도 때로는 작은 앱에서보기와 함께 섞여서 끝나는 경우가 있습니다.

나는 당신이 넣을 것을 제안합니다 :

public void actionPerformed(ActionEvent e)

컨트롤러에서. 그런 다음 뷰의 액션 리스너가 컨트롤러에 위임되어야합니다.

유효성 검사 부분은 뷰 또는 컨트롤러에 넣을 수 있습니다. 개인적으로 컨트롤러에 속한다고 생각합니다.

Passive View와 Supervising Presenter (기본적으로 Model View Presenter가 적어도 Fowler에 의해 분할되는 것)를 살펴 보는 것이 좋습니다. 보다:

http://www.martinfowler.com/eaaDev/PassiveScreen.html

http://www.martinfowler.com/eaaDev/SupervisingPresenter.html


3

다음은 내가 사용하는 경험 법칙입니다 . 페이지 의 작업에 특별히 사용하는 절차 인 경우 모델이 아닌 컨트롤러에 속합니다. 모델은 데이터 스토리지에 대한 일관된 추상화 만 제공해야합니다.

MVC는 이해했지만 실제로는 이해하지 못하는 개발자가 작성한 대형 웹 응용 프로그램으로 작업 한 후이 문제를 해결했습니다. 그들의 "컨트롤러"는 여타 호출되지 않는 정적 클래스 메소드를 호출하는 여덟 줄로 줄어 듭니다. 이것을 리팩토링하면 세 가지 일을 할 수 있습니다 : 모든 SQL을 데이터 액세스 계층 (일명 모델)으로 옮기고, 컨트롤러 코드를 좀 더 장황하지만 이해하기 쉽게 만들고, 오래된 "모델"파일을 줄입니다. :-)


1

또한 각 Swing 위젯은 3 개의 MVC 컴포넌트를 포함하는 것으로 간주 될 수 있습니다. 각각에는 Model (예 : ButtonModel), View (BasicButtonUI) 및 Control (JButton 자체)이 있습니다.


1

컨트롤러에 넣는 것에 대해 본질적으로 옳습니다. 모델이 뷰와 상호 작용해야하는 유일한 방법입니다. 수행 된 작업은 View에 배치 할 수 있지만 실제 기능은 Controller 역할을하는 다른 클래스에 배치 될 수 있습니다. 이 작업을 수행하려면 동일한 수신자를 가진 모든 명령을 추상화하는 방법 인 명령 패턴을 살펴 보는 것이 좋습니다. 이 유감으로 죄송합니다.

어쨌든, 올바른 MVC 구현은 다음과 같은 상호 작용 만합니다. 모델->보기보기-> 컨트롤러 컨트롤러->보기

다른 상호 작용이있을 수있는 유일한 장소는 관찰자를 사용하여보기를 업데이트하는 경우보기는 컨트롤러에 필요한 정보를 요청해야합니다.


0

내가 이해하는 것처럼 Controller는 사용자 인터페이스 작업에서 응용 프로그램 수준 작업으로 변환합니다. 예를 들어, 비디오 게임에서 컨트롤러는 "마우스를 너무 많이 움직였다"를 "그러한 방향으로보고 싶을 때"로 번역 할 수 있습니다. "이것을 인쇄"하지만 개념은 동일합니다.


0

따라서 사용자 중심의 입력 / 동작 (보기, 데이터 및 명백한 _Model 항목을 제외한 다른 모든 것에 대한 _Logic)을 처리하고 반응하기 위해 주로 컨트롤러를 사용합니다.

(1) (응답, 반응-사용자에 대한 응답으로 웹앱의 기능) Blog_Controller

-> 메인 ()

-> handleSubmit_AddNewCustomer ()

-> verifyUser_HasProperAuth ()

(2) ( "비즈니스"논리, 웹앱이 무엇을 어떻게 "생각하는지") Blog_Logic

-> sanityCheck_AddNewCustomer ()

-> handleUsernameChange ()

-> sendEmail_NotifyRequestedUpdate ()

(3) (보기, 포털, 웹앱이 나타나는 방법) Blog_View

-> genWelcome ()

-> genForm_AddNewBlogEntry ()

-> genPage_DataEntryForm ()

(4) ( 각 Blog * 클래스 _ construct () 에서 획득 한 모든 웹앱 / 메모리 데이터를 하나의 객체로 유지하는 데 사용되는 데이터 객체 만) Blog_Meta

(5) (기본 데이터 계층, DB 읽기 / 쓰기) Blog_Model

-> saveDataToMemcache ()

-> saveDataToMongo ()

-> saveDataToSql ()

-> loadData ()

때때로 우리는 C 또는 L에서 방법을 넣을 위치에 대해 약간 혼란스러워합니다. 그러나 모델은 견고하고 명확하며 모든 인 메모리 데이터는 _Meta에 있기 때문에 그다지 쉬운 것은 아닙니다. . 우리의 가장 큰 도약은 다양한 _C, _L 및 _Model 객체에서 모든 크 러드를 제거하고 모든 것을 정신적으로 쉽게 관리 할 수있게했고, 한 번에 한 번에 "종속성 주입"또는 모든 데이터와 함께 전체 환경을 전달하는 방법 ( "테스트"환경을 쉽게 만들 수있는 보너스)이라고합니다.

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