Làm thế nào để xác định những gì nên có bộ điều khiển tương ứng của riêng mình?


10

Tôi đang sử dụng mẫu MVC trong ứng dụng web của mình được xây dựng bằng PHP.

Tôi luôn đấu tranh để xác định xem tôi có cần một bộ điều khiển chuyên dụng mới cho một tập hợp các hành động hay không nếu tôi nên đặt chúng bên trong một bộ điều khiển đã có sẵn.

Có bất kỳ quy tắc tốt để làm theo khi tạo bộ điều khiển?

Ví dụ tôi có thể có:

AuthenticationController với hành động:

  • index() để hiển thị mẫu đăng nhập.
  • submit() để xử lý đệ trình mẫu.
  • logout(), tự giải thích.

HOẶC LÀ

LoginController với hành động:

  • index() để hiển thị mẫu đăng nhập.
  • submit() để xử lý đệ trình mẫu.

LogoutController với hành động:

  • index() để xử lý đăng xuất.

HOẶC LÀ

AccountController với hành động:

  • loginGet() để hiển thị mẫu đăng nhập.
  • loginPost() để xử lý nộp mẫu đăng nhập.
  • logoutGet() để xử lý đăng xuất.
  • registerGet() để hiển thị mẫu đăng ký.
  • registerPost() để xử lý đệ trình mẫu.

    Và bất kỳ hành động nào khác có liên quan đến một tài khoản.


Có thể có một cái nhìn vào thiết kế RESTful. Nó không giải quyết mọi vấn đề duy nhất thuộc loại này, nhưng cung cấp cho bạn một hướng rất tốt về cách nghĩ về nó.
thorsten müller

Câu trả lời:


3

Để tìm nhóm phù hợp cho bộ điều khiển, hãy nghĩ đến thử nghiệm .

(Ngay cả khi bạn không thực sự thực hiện bất kỳ thử nghiệm nào, nghĩ về cách bạn sẽ tiến hành kiểm tra các bộ điều khiển của bạn sẽ cung cấp cho bạn một số hiểu biết rất tốt về cách cấu trúc chúng.)

Bản thân An AuthenticationControllerkhông thể kiểm tra được, vì nó chỉ chứa chức năng đăng nhập và đăng xuất, nhưng mã kiểm tra của bạn sẽ cần bằng cách nào đó tạo tài khoản giả cho mục đích kiểm tra trước khi có thể kiểm tra đăng nhập thành công. Bạn có thể bỏ qua kiểm tra hệ thống con và trực tiếp đến mô hình của mình để tạo tài khoản thử nghiệm, nhưng sau đó bạn sẽ có một thử nghiệm dễ vỡ trong tay: nếu mô hình thay đổi, bạn sẽ phải sửa đổi không chỉ mã kiểm tra mô hình, nhưng cũng có mã kiểm tra bộ điều khiển, mặc dù giao diện và hành vi của bộ điều khiển vẫn không thay đổi. Điều đó không hợp lý.

A LoginControllerkhông phù hợp vì những lý do tương tự: bạn không thể kiểm tra nó mà không tạo tài khoản trước và thậm chí còn có nhiều thứ bạn không thể kiểm tra, ví dụ như ngăn chặn đăng nhập trùng lặp nhưng sau đó cho phép người dùng đăng nhập sau khi đăng xuất. (Vì bộ điều khiển này không có chức năng đăng xuất.)

An AccountControllersẽ cung cấp cho bạn mọi thứ bạn cần để thực hiện kiểm tra: bạn có thể tạo tài khoản kiểm tra và sau đó thử đăng nhập, bạn có thể xóa tài khoản và sau đó đảm bảo bạn không thể đăng nhập nữa, bạn có thể thay đổi mật khẩu và đảm bảo rằng mật khẩu phải được sử dụng để đăng nhập, v.v.

Để kết luận: để viết ngay cả bộ thử nghiệm nhỏ nhất, bạn sẽ cần phải cung cấp tất cả các chức năng AccountControllercó sẵn cho nó. Việc chia nó xuống các bộ điều khiển nhỏ hơn dường như mang lại các bộ điều khiển khuyết tật với chức năng không đủ cho một thử nghiệm thích hợp. Đây là một dấu hiệu rất tốt cho thấy chức năng của AccountControllerlà phân ngành nhỏ nhất có ý nghĩa.

Và nói chung, phương pháp "nghĩ về thử nghiệm" sẽ hoạt động không chỉ trong kịch bản cụ thể này, mà trong bất kỳ kịch bản tương tự nào bạn gặp trong tương lai.


1

Câu trả lời không rõ ràng

Xin vui lòng cho tôi làm rõ một vài điều trước khi tôi sẽ đưa ra bất kỳ tuyên bố trả lời. Đầu tiên:

Bộ điều khiển là gì?

Bộ điều khiển là một phần của hệ thống kiểm soát yêu cầu - sau khi gửi đi. Vì vậy, chúng ta có thể định nghĩa nó là một số hành động liên quan đến ... cái gì?

Phạm vi của bộ điều khiển là gì?

Và đó là một phần hoặc ít hơn khi chúng ta sẽ có bất kỳ câu trả lời. Bạn nghĩ sao? Nó có phải là bộ điều khiển của mọi thứ (ví dụ như Tài khoản) hoặc bộ điều khiển hành động không? Tất nhiên nó là bộ điều khiển của một số mô hình hoặc một số thứ trừu tượng hơn cung cấp các hành động trên nó.

Câu trả lời là...

Trình xác thực với các hành động:

  • index () để hiển thị mẫu đăng nhập.
  • nộp () để xử lý đệ trình mẫu.
  • đăng xuất (), tự giải thích.

Không, xác thực là một quá trình. Đừng đi theo cách đó.

Đăng nhập Trình điều khiển với các hành động:

  • index () để hiển thị mẫu đăng nhập.
  • nộp () để xử lý đệ trình mẫu.

Tương tự ở đây. Đăng nhập - hành động. Tốt hơn đừng tạo bộ điều khiển hành động (bạn không có mô hình tương quan với nó).

Tài khoản kiểm soát với các hành động:

  • loginGet () để hiển thị mẫu đăng nhập.
  • loginPost () để xử lý việc gửi biểu mẫu đăng nhập.
  • logoutGet () để xử lý đăng xuất.
  • registerGet () để hiển thị mẫu đăng ký.
  • registerPost () để xử lý việc gửi biểu mẫu.

Khá tốt, nhưng tôi không tin rằng việc xây dựng bộ điều khiển cấp thấp (bộ điều khiển là trừu tượng hóa) là đáng để mang lại. Dù sao, việc tạo phương thức với * Nhận hoặc * Đăng không rõ ràng.

Bất kì lời đề nghị nào?

Vâng, hãy xem xét nó:

Tài khoản kiểm soát:

  • đăng nhập (AccountModel)
  • đăng xuất (AccountModel)
  • đăng ký (AccountModel)
  • mục lục()

Và mô hình liên quan đến nó, lớp Tài khoản ofc. Nó sẽ cho bạn cơ hội để di chuyển cặp điều khiển mô hình của bạn sang một nơi khác (nếu nó không cần thiết) và tạo một mã rõ ràng (rõ ràng login()phương thức này có nghĩa là gì). Stincking để mô hình thực sự nổi tiếng đặc biệt là với các ứng dụng CRUD và có thể đó là một cách cho bạn.


1

Bộ điều khiển thường được tạo cho một tài nguyên nhất định (một lớp thực thể, một bảng trong cơ sở dữ liệu), nhưng cũng có thể được tạo để nhóm các hành động chịu trách nhiệm với một phần nhất định của ứng dụng. Trong ví dụ của bạn, đó sẽ là một bộ điều khiển xử lý bảo mật cho ứng dụng:

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();
}

Lưu ý : không đặt các hành động liên quan đến bảo mật và hành động hồ sơ người dùng trong cùng một bộ điều khiển; nó có thể có ý nghĩa bởi vì chúng có liên quan đến người dùng, nhưng một người nên xử lý xác thực và người kia nên xử lý các cập nhật email, tên, v.v.

Với các bộ điều khiển được tạo cho tài nguyên (giả sử Task), bạn sẽ có các hành động CRUD thông thường :

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()
}

Tất nhiên, bạn có khả năng thêm các tài nguyên liên quan vào cùng một bộ điều khiển. Ví dụ, bạn có thực thể Businessvà mỗi người có một vài BusinessServicethực thể. Một bộ điều khiển cho nó có thể trông như thế này:

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);
}

Cách tiếp cận này có ý nghĩa khi các thực thể con liên quan không thể tồn tại mà không có thực thể cha mẹ.

Đây là những khuyến nghị của tôi:

  • tạo bộ điều khiển dựa trên một nhóm các hoạt động liên quan (xử lý một số trách nhiệm nhất định như bảo mật hoặc hoạt động CRUD trên tài nguyên, v.v.);
  • đối với các bộ điều khiển dựa trên tài nguyên, không thêm các hành động không cần thiết (nếu bạn không được yêu cầu cập nhật tài nguyên, không thêm hành động cập nhật);
  • bạn có thể thêm các hành động "tùy chỉnh" để đơn giản hóa mọi thứ (ví dụ: bạn có một Subscriptionthực thể có sẵn dựa trên số lượng mục nhập hạn chế, bạn có thể thêm một hành động mới vào bộ điều khiển có tên use()với mục đích duy nhất là trừ một mục từ Subscription)
  • giữ mọi thứ đơn giản - đừng làm lộn xộn bộ điều khiển của bạn với một số lượng lớn hành động và logic phức tạp, hãy cố gắng đơn giản hóa mọi thứ bằng cách giảm số lượng hành động hoặc tạo hai bộ điều khiển;
  • nếu bạn đang sử dụng một khung tập trung MVC, hãy làm theo các hướng dẫn thực hành tốt nhất của họ (nếu họ có nó).

Một số tài nguyên để đọc thêm ở đây .


0

Tôi thấy hai "lực lượng" thiết kế đối kháng (không dành riêng cho bộ điều khiển):

  • tính cố kết - bộ điều khiển nên nhóm các hành động liên quan
  • đơn giản - bộ điều khiển nên càng nhỏ càng tốt để quản lý sự phức tạp của chúng

Từ quan điểm cố kết, cả ba hành động (đăng nhập, đăng xuất, đăng ký) đều có liên quan, nhưng đăng nhập & đăng xuất nhiều hơn đăng ký. Chúng có liên quan về mặt ngữ nghĩa (một cái là đảo ngược cái kia) và hoàn toàn có thể cũng sẽ sử dụng cùng các đối tượng dịch vụ (việc triển khai của chúng cũng gắn kết).

Bản năng đầu tiên của tôi sẽ là đăng nhập nhóm và đăng xuất vào một bộ điều khiển. Nhưng nếu việc triển khai bộ điều khiển đăng nhập và đăng xuất không đơn giản như vậy (ví dụ: đăng nhập có captcha, nhiều phương thức xác thực hơn, v.v.), tôi sẽ không gặp vấn đề gì khi chia chúng thành LoginContoder và LogoutContoder để duy trì sự đơn giản. Trường hợp ngưỡng phức tạp này (khi bạn nên bắt đầu chia bộ điều khiển) nằm ở một chút cá nhân.

Cũng cần nhớ rằng, bất cứ điều gì bạn thiết kế mã ban đầu, bạn có thể (và nên) cấu trúc lại mã khi nó thay đổi. Trong trường hợp này, việc bắt đầu với thiết kế đơn giản (có một Trình xác thực) là khá điển hình và theo thời gian, bạn sẽ nhận được nhiều yêu cầu hơn sẽ làm phức tạp mã. Khi nó vượt qua ngưỡng phức tạp, bạn nên cấu trúc lại nó thành hai bộ điều khiển.

BTW, mã của bạn cho thấy rằng bạn đang đăng xuất người dùng với yêu cầu GET. Đó là một ý tưởng tồi vì HTTP GET sẽ không có giá trị (không nên sửa đổi trạng thái của ứng dụng).


0

Dưới đây là một vài quy tắc của ngón tay cái:

  • Sắp xếp theo chủ đề hoặc chủ đề, với tên bộ điều khiển là tên của chủ đề.

  • Hãy nhớ rằng tên của bộ điều khiển sẽ xuất hiện trong URL, hiển thị cho người dùng của bạn, vì vậy tốt nhất là nó sẽ có ý nghĩa với họ.

Trong tình huống bạn đề cập (xác thực), nhóm MVC đã viết trình điều khiển cho bạn. Mở Visual Studio 2013 và sau đó nhấp

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

AccountControll.cs chứa tất cả các phương thức để quản lý tài khoản người dùng:

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

Vì vậy, họ đã tổ chức theo chủ đề "Tài khoản người dùng và xác thực", với tên chủ đề hiển thị "Tài khoản".


0

Thuật ngữ

Tôi tin rằng đó là một quan niệm sai lầm lớn khi gọi một lớp có chứa một số phương thức liên quan đến HTTP là "bộ điều khiển".

Trình điều khiển là một phương thức xử lý yêu cầu, nhưng không phải là một lớp có chứa các phương thức đó . Vì vậy, index(), submit(), logout()là bộ điều khiển.

Lớp chứa loại phương thức đó được đặt tên là "trình điều khiển" chỉ vì nó tạo thành một nhóm các bộ điều khiển và đang đóng một vai trò của không gian tên "mức dưới cùng". Trong ngôn ngữ FP (như Haskell), nó sẽ chỉ là một mô-đun. Đó là một thực hành tốt để giữ cho các lớp "trình điều khiển" đó không trạng thái nhất có thể trong các ngôn ngữ OOP, ngoại trừ các tham chiếu đến các dịch vụ và các nội dung khác trong toàn chương trình.

Câu trả lời

Với thuật ngữ được sắp xếp, câu hỏi là "chúng ta nên tách bộ điều khiển thành các không gian tên / mô-đun như thế nào?" Tôi nghĩ câu trả lời là: các bộ điều khiển bên trong một không gian tên / mô-đun duy nhất sẽ xử lý cùng loại dữ liệu . Ví dụ, UserControllergiao dịch chủ yếu với các thể hiện của Userlớp, nhưng đôi khi chạm vào những thứ liên quan khác, nếu được yêu cầu.

Kể từ login, logoutvà các hành động khác như vậy chủ yếu đối phó với phiên giao dịch, nó có lẽ tốt nhất để đặt chúng bên trong SessionController, và indexđiều khiển, mà chỉ in một hình thức, nên được đặt vào LoginPageController, vì nó rõ ràng là giao dịch với trang đăng nhập. Thật ý nghĩa khi đặt kết xuất HTML và quản lý phiên vào một lớp duy nhất và điều đó sẽ vi phạm SRP và có thể là một loạt các thực tiễn tốt khác.

Nguyên tắc chung

Khi bạn gặp khó khăn khi quyết định đặt một đoạn mã, hãy bắt đầu với dữ liệu (và loại) mà bạn xử lý.


2
Xin lỗi, đó là Hành động, không phải Bộ điều khiển :)
JK01

@ JK01 Đó là những gì bạn gọi chúng. Đó là thuật ngữ, bạn biết đấy. Và có những khung gọi các hàm đó là "bộ điều khiển" (hoặc "trình xử lý"), vì có nhiều khung không tổ chức chúng thành các lớp, vì không gian tên / mô-đun đã đủ. Bạn có thể sử dụng bất kỳ thuật ngữ nào bạn thích, đó chỉ là từ, nhưng tôi nghĩ rằng có ít thuật ngữ sẽ tốt hơn.
scriptin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.