자체 컨트롤러를 가져와야하는 것을 어떻게 결정합니까?


10

PHP로 작성된 웹 응용 프로그램에서 MVC 패턴을 사용하고 있습니다.

나는 항상 일련의 작업을 위해 새로운 전용 컨트롤러가 필요한지 또는 기존 컨트롤러 내에 배치 해야하는지 결정하기 위해 고심하고 있습니다.

컨트롤러를 만들 때 따라야 할 규칙이 있습니까?

예를 들어 다음을 가질 수 있습니다.

AuthenticationController 행동으로 :

  • index() 로그인 양식을 표시합니다.
  • submit() 양식 제출을 처리합니다.
  • logout()자명하다.

또는

LoginController 행동으로 :

  • index() 로그인 양식을 표시합니다.
  • submit() 양식 제출을 처리합니다.

LogoutController 행동으로 :

  • index() 로그 아웃을 처리합니다.

또는

AccountController 행동으로 :

  • loginGet() 로그인 양식을 표시합니다.
  • loginPost() 로그인 양식 제출을 처리합니다.
  • logoutGet() 로그 아웃을 처리합니다.
  • registerGet() 등록 양식을 표시합니다.
  • registerPost() 양식 제출을 처리합니다.

    그리고 계정과 관련된 다른 작업.


RESTful 디자인을 살펴보십시오. 이런 종류의 모든 문제를 해결하지는 못하지만 그것에 대해 생각하는 방법은 매우 좋습니다.
thorsten müller

답변:


3

컨트롤러에 적합한 그룹을 찾으 려면 테스트를 생각하십시오 .

(실제로 테스트를 수행하지 않더라도 컨트롤러 테스트 방법을 생각하면 컨트롤러를 구성하는 방법에 대한 훌륭한 통찰력을 얻을 수 있습니다.)

AuthenticationController단지에 로깅을위한 기능을 포함하고 로그 아웃하지만 테스트 코드가 어떻게 든 성공적으로 로그인을 테스트하기 전에 테스트 목적 가짜 계정을 생성해야하므로, 그 자체로 검증하지 않습니다. 테스트 대상 서브 시스템을 우회하고 테스트 계정을 작성하기 위해 모델로 직접 이동할 수 있지만 손에 약한 테스트가 필요합니다. 모델이 변경되면 테스트 할 코드뿐만 아니라 수정해야합니다. 컨트롤러의 인터페이스와 동작이 변경되지 않았음에도 불구하고 모델뿐만 아니라 컨트롤러를 테스트하는 코드도 있습니다. 불합리합니다.

A LoginController는 같은 이유로 부적합합니다. 먼저 계정을 만들지 않고 테스트 할 수 없으며, 중복 로그인을 방지하지만 로그 아웃 한 후 사용자가 로그인 할 수 있도록하는 등 테스트 할 수없는 것이 더 있습니다. 이 컨트롤러에는 로그 아웃 기능이 없습니다.

AccountController, 당신은 테스트 계정을 생성하고 로그인을 시도 할 수 있습니다 당신은 계정을 삭제하고 있는지 확인은 로그인 더 이상, 당신은 암호를 변경할 수 있는지 그 수 없습니다 : 당신은 위해 필요한 당신에게 제공합니다 모든 것을 당신의 테스트를 수행합니다 로그인 등을하려면 올바른 비밀번호를 사용해야합니다.

결론 : 가장 작은 테스트 스위트를 작성하려면 AccountController사용 가능한 모든 기능을 사용할 수 있어야합니다. 작은 컨트롤러로 세분화하면 적절한 테스트를위한 기능이 불충분 한 장애가있는 컨트롤러를 생성하는 것으로 보입니다. 이는 기능이 AccountController가장 작은 세분화라는 의미입니다.

그리고 일반적으로 말하면, "테스트에 대한 생각"접근 방식은이 특정 시나리오뿐만 아니라 앞으로도 비슷한 시나리오에서 작동합니다.


1

대답은 분명하지 않습니다

대답을하기 전에 몇 가지 사항을 명확히 해주세요. 가장 먼저:

컨트롤러 란 무엇입니까?

컨트롤러는 디스패치 후 요청 을 제어 하는 시스템의 일부입니다 . 따라서 우리는 그것을 무엇과 관련된 일련의 행동 으로 정의 할 수 있습니다 .

컨트롤러의 범위는 무엇입니까?

그리고 그것은 우리가 대답 할 때 어느 정도입니다. 어떻게 생각해? 사물 컨트롤러 (예 : 계정) 또는 작업 컨트롤러입니까? 물론 일부 모델 의 컨트롤러 또는 이에 대한 조치를 제공하는 더 추상적 인 컨트롤러입니다 .

정답은...

동작이있는 AuthenticationController :

  • 로그인 양식을 표시하는 index ().
  • submit ()은 양식 제출을 처리합니다.
  • 설명이 필요없는 logout ().

아냐, 인증은 과정이다. 그런 식으로 가지 마십시오.

액션이있는 LoginController :

  • 로그인 양식을 표시하는 index ().
  • submit ()은 양식 제출을 처리합니다.

여기도 마찬가지입니다. 로그인-조치. 액션 컨트롤러를 만들지 않는 것이 좋습니다 (상관 된 모델이 없습니다).

조치가있는 AccountController :

  • loginGet ()을 사용하여 로그인 양식을 표시하십시오.
  • loginPost ()는 로그인 양식 제출을 처리합니다.
  • logoutGet ()은 로그 아웃을 처리합니다.
  • registerGet ()을 사용하여 등록 양식을 표시하십시오.
  • 양식 제출을 처리하는 registerPost ()

꽤 좋지만 저수준 컨트롤러 (컨트롤러 자체 추상화)를 구축하는 것이 가치가 있다고 확신하지 않습니다. 어쨌든 * Get 또는 * Post로 메소드를 작성하는 것은 확실하지 않습니다.

어떠한 제안?

그렇습니다.

AccountController :

  • 로그인 (계정 모델)
  • 로그 아웃 (계정 모델)
  • 등록 (계정 모델)
  • 인덱스()

그리고 관련 모델, ofc 계정 클래스. 모델 컨트롤러 쌍을 다른 곳으로 옮기고 (필요한 경우) 명확한 코드를 만들 수 있습니다 ( login()메서드가 의미 하는 바가 분명합니다 ). 특히 CRUD 응용 프로그램에서 모델을 선호하는 것은 정말 유명하며 아마도 당신에게 적합한 방법 일 것입니다.


1

컨트롤러는 일반적으로 특정 리소스 (엔터티 클래스, 데이터베이스의 테이블)에 대해 만들어 지지만 응용 프로그램의 특정 부분을 담당하는 작업을 그룹화하기 위해 만들 수도 있습니다. 귀하의 예에서 이는 애플리케이션의 보안을 처리하는 컨트롤러입니다.

class SecurityController
{
    // can handle both the login page display and
    // the login page submission
    login(); 

    logout();

    register();

    // optional: confirm account after registration
    confirm();

    // displays the forgot password page
    forgotPassword();

    // displays the reset password page
    // and handle the form submission
    resetPassword();
}

참고 : 보안 관련 작업과 사용자 프로필 작업을 동일한 컨트롤러에 넣지 마십시오. 사용자와 관련되어 있기 때문에 의미가 있지만 하나는 인증을 처리하고 다른 하나는 전자 메일, 이름 등의 업데이트를 처리해야합니다.

리소스에 대해 컨트롤러를 Task만들면 일반적인 CRUD 작업이 수행됩니다.

class TasksController
{
    // usually displays a paginated list of tasks
    index();

    // displays a certain task, based on an identifier
    show(id);

    // displays page with form and
    // handles form submission for creating
    // new tasks
    create();

    // same as create(), but for changing records
    update(id);     

    // displays confirmation message
    // and handles submissions in case of confirmation
    delete()
}

물론, 동일한 컨트롤러에 관련 리소스를 추가 할 수도 있습니다. 예를 들어 엔티티 Business가 있고 각 BusinessService엔티티에 여러 엔티티 가 있다고 가정하십시오 . 컨트롤러는 다음과 같습니다.

class BusinessController
{
    index();

    show(id);

    create();

    update(id);

    delete();

    // display the business services for a certain business
    listBusinessServices(businessId);

    // displays a certain business service
    showBusinessService(id);

    // create a new business service for a certain business
    createBusinessService(businessId);

    // updates a certain business service
    updateBusinessService(id);

    // deletes a certain business service
    deleteBusinessService(id);
}

이 접근 방식은 관련 하위 항목이 상위 항목없이 존재할 수없는 경우에 적합합니다.

이것들은 나의 추천입니다 :

  • 관련 작업 그룹 (보안 또는 리소스에 대한 CRUD 작업과 같은 특정 책임 처리)을 기반으로 컨트롤러를 만듭니다.
  • 리소스 기반 컨트롤러의 경우 불필요한 작업을 추가하지 마십시오 (리소스를 업데이트하지 않을 경우 업데이트 작업을 추가하지 마십시오).
  • "사용자 정의"작업을 추가하여 작업을 단순화 할 수 있습니다 (예 : Subscription제한된 수의 항목을 기반으로 가용성 이있는 엔터티가있는 경우 컨트롤러 use()에서 하나의 항목을 빼는 단일 목적을 가진 컨트롤러에 새 작업을 추가 할 수 있음 Subscription)
  • 일을 단순하게 유지하십시오-수많은 동작과 복잡한 논리로 컨트롤러를 복잡하게 만들지 말고 동작 수를 줄이거 나 두 개의 컨트롤러를 만들어서 단순화하십시오.
  • MVC 중심 프레임 워크를 사용하는 경우 모범 사례 지침 (있는 경우)을 따르십시오.

자세한 내용은 여기를 참조하십시오 .


0

두 가지 적대적 디자인 "힘"(컨트롤러 전용이 아님)을 봅니다.

  • 응집력-컨트롤러는 관련 작업을 그룹화해야합니다
  • 단순성-컨트롤러는 복잡성을 관리하기 위해 가능한 한 작아야합니다

응집력의 관점에서, 세 가지 동작 (로그인, 로그 아웃, 등록)은 모두 관련되어 있지만, 로그인 및 로그 아웃은 등록보다 훨씬 더 중요합니다. 그것들은 의미 적으로 관련되어 있으며 (하나는 다른 것의 반전이다) 아마도 동일한 서비스 객체를 사용할 것입니다 (구현도 응집력이 있습니다).

첫 번째는 로그인과 로그 아웃을 하나의 컨트롤러로 그룹화하는 것입니다. 그러나 로그인 및 로그 아웃 컨트롤러 구현이 그렇게 간단하지 않은 경우 (예 : 로그인에 보안 문자, 더 많은 인증 방법 등이 있음) 단순성을 유지하기 위해 LoginController와 LogoutController로 나누는 데 아무런 문제가 없습니다. 이 복잡성 임계 값 (컨트롤러 분할을 시작해야 할 때)이있는 곳은 약간 개인적입니다.

또한 코드를 처음 디자인 할 때마다 코드가 변경 될 때 리팩토링 할 수 있다는 점을 기억하십시오. 이 경우 단순한 디자인 (AuthorityController가 하나 있음)으로 시작하는 것이 일반적이며 시간이 지남에 따라 코드를 복잡하게하는 더 많은 요구 사항을 받게됩니다. 복잡성 임계 값을 초과하면 두 컨트롤러로 리팩토링해야합니다.

BTW, 귀하의 코드는 GET 요청으로 사용자를 로그 아웃한다고 제안합니다. HTTP GET은 nullipotent (애플리케이션의 상태를 수정해서는 안 됨)이기 때문에 나쁜 생각입니다.


0

다음은 몇 가지 일반적인 규칙입니다.

  • 컨트롤러 이름이 주제 이름 인 주제 또는 주제별로 구성하십시오.

  • 컨트롤러 이름은 URL에 나타나고 사용자에게 표시되므로 바람직하게 이해해야합니다.

귀하가 언급 한 (인증) 상황에서 MVC 팀은 이미 귀하를 위해 컨트롤러를 작성했습니다. Visual Studio 2013을 열고 클릭

File / New / Project... 
Search installed templates for "ASP.NET MVC4 Web Application"
Choose "Internet Application" / OK.

AccountController.cs에는 사용자 계정 관리를위한 모든 방법이 포함되어 있습니다.

Login()
Logoff()
Register()
Disassociate()
Manage()
ExternalLogin()

따라서 주제 이름이 "계정"인 주제 "사용자 계정 및 인증"으로 구성되었습니다.


0

술어

HTTP 관련 메소드를 포함하는 클래스를 "컨트롤러"라고 부르는 것은 오해라고 생각합니다.

Controller는 요청을 처리하는 메소드이지만 그러한 메소드를 포함하는 클래스는 아닙니다 . 그래서, index(), submit(), logout()컨트롤러이다.

이러한 종류의 메소드를 포함하는 클래스는 컨트롤러 그룹을 구성하고 "하단 레벨"네임 스페이스 역할을하기 때문에 "컨트롤러"라고합니다. FP 언어 (예 : Haskell)에서는 모듈 일뿐입니다. 서비스 및 기타 프로그램 전반에 대한 참조를 제외하고 OOP 언어에서 이러한 "컨트롤러"클래스를 가능한 한 상태 비 저장 상태로 유지하는 것이 좋습니다.

대답

용어를 정리하면 "컨트롤러를 네임 스페이스 / 모듈로 어떻게 분리해야합니까?" 답은 단일 네임 스페이스 / 모듈 내의 컨트롤러가 동일한 종류의 데이터를 처리해야한다는 것입니다 . 예를 들어, UserController거래 주로 의 인스턴스 User클래스,하지만 때때로 필요한 경우, 기타 관련 물건을 만지는.

이후 login, logout등의 행동이 주로 세션을 처리하고, 아마 가장 안쪽을 넣어 SessionController, 그리고 index단지 양식을 출력 컨트롤러는,에 배치해야 LoginPageController그것은 분명히 로그인 페이지 다루고 있기 때문에. HTML 렌더링 및 세션 관리를 단일 클래스에 넣는 것은 약간 의미가 있으며, 이는 SRP 및 기타 여러 가지 유용한 방법 을 위반할 수 있습니다.

일반적인 원리

코드를 넣을 위치를 결정하는 데 어려움이 있으면 처리하는 데이터 (및 유형)로 시작하십시오.


2
죄송합니다. 컨트롤러가 아닌 액션입니다. :)
JK01

@ JK01 그것들을 당신이 부르는 것입니다. 그것은 용어입니다. 네임 스페이스 / 모듈이 이미 충분하기 때문에 이러한 기능을 "컨트롤러"(또는 "핸들러")라고하는 프레임 워크가 있습니다. 원하는 용어를 사용할 수 있습니다. 단어 일 뿐이지 만 용어가 적을수록 좋습니다.
scriptin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.