Kiến trúc sạch: Mô hình View là gì?


13

Trong cuốn sách 'Kiến trúc sạch', chú Bob nói rằng Người thuyết trình nên đưa dữ liệu mà nó nhận được vào thứ mà ông gọi là 'Mô hình xem'.

nhập mô tả hình ảnh ở đây

Đây có phải là điều tương tự như 'ViewModel' từ mẫu thiết kế Model-View-ViewModel (MVVM) hay nó là một Đối tượng truyền dữ liệu đơn giản (DTO)?

Nếu nó không phải là một DTO đơn giản, thì nó liên quan đến View như thế nào? Chế độ xem có nhận được cập nhật từ nó thông qua mối quan hệ Observer không?

Tôi đoán là nó giống với ViewModel từ MVVM hơn, bởi vì trong Chương 23 của cuốn sách, Robert Martin nói:

Công việc của [Người thuyết trình] là chấp nhận dữ liệu từ ứng dụng và định dạng nó để trình bày để Chế độ xem có thể chỉ cần di chuyển nó đến màn hình. Ví dụ: nếu ứng dụng muốn một ngày được hiển thị trong một trường, nó sẽ trao cho Người trình bày một đối tượng Ngày. Sau đó, Người trình bày sẽ định dạng dữ liệu đó thành một chuỗi thích hợp và đặt nó vào một cấu trúc dữ liệu đơn giản được gọi là mô hình Chế độ xem, nơi Chế độ xem có thể tìm thấy dữ liệu đó.

Điều này ngụ ý rằng Chế độ xem được kết nối bằng cách nào đó với ViewModel, trái ngược với việc chỉ đơn giản nhận nó làm đối số chức năng (ví dụ như trường hợp với DTO).

Một lý do khác khiến tôi nghĩ điều này là bởi vì nếu bạn nhìn vào hình ảnh, Người thuyết trình sử dụng Mô hình Chế độ xem chứ không phải Chế độ xem. Trong khi đó, Người trình bày sử dụng cả Ranh giới đầu ra và Dữ liệu đầu ra DTO.

Nếu nó không phải là DTO hay ViewModel từ MVVM, vui lòng giải thích chi tiết về nó.


Tôi nghĩ rằng câu trả lời là "nó phụ thuộc." Nếu đó là một ứng dụng web thì mô hình xem về cơ bản là DTO vì cuối cùng nó được tuần tự hóa dưới dạng chuỗi HTML. Mặt khác, một mô hình khung nhìn chỉ là một đối tượng chuyên biệt để hiển thị dữ liệu cho khung nhìn.
Greg Burghardt

Trong MVVM (WPF, Winforms ứng dụng) ViewModellà wrapper cho Controller, PresenterViewModeltrong kiến trúc sạch Bác Bob.
Fabio

@Greg Burghardt - Khi ViewModel là cấu trúc dữ liệu chuyên biệt, View được thông báo về các thay đổi như thế nào?
Fearnbuster

@Fabio - Nếu tôi hiểu chính xác ý của bạn thì bạn nói rằng trong mẫu MVVM, ViewModel có tương đương với tất cả các thành phần nằm trong nhóm bên trái của sơ đồ không? Nếu điều đó đúng với kiến ​​trúc của chú Bob, thì tại sao ông lại liệt kê riêng Người điều khiển và Người thuyết trình?
Fearnbuster

Tôi nghĩ rằng ông đã tách các trình xử lý đầu vào và đầu ra cho các đối tượng / lớp khác nhau. Trong MVVM, nó có thể là Controller-> ICommandPresenter-> data-binding mechanism.
Fabio

Câu trả lời:


17

Đây có phải là điều tương tự như 'ViewModel' từ mẫu thiết kế Model-View-ViewModel (MVVM)

Không.

Đó sẽ là thế này :

nhập mô tả hình ảnh ở đây

Điều đó có chu kỳ. Chú Bob đã cẩn thận tránh chu kỳ .

Thay vào đó bạn có điều này:

nhập mô tả hình ảnh ở đây

Mà chắc chắn không có chu kỳ. Nhưng nó khiến bạn tự hỏi làm thế nào quan điểm biết về một bản cập nhật. Chúng ta sẽ đến đó trong giây lát.

hoặc nó là một đối tượng truyền dữ liệu đơn giản (DTO)?

Để trích dẫn Bob từ trang trước:

Bạn có thể sử dụng các cấu trúc cơ bản hoặc các đối tượng truyền dữ liệu đơn giản nếu bạn muốn. Hoặc bạn có thể đóng gói nó thành một hashmap hoặc xây dựng nó thành một đối tượng.

Kiến trúc sạch p207

Vì vậy, chắc chắn, nếu bạn thích.

Nhưng tôi cực kỳ nghi ngờ những gì thực sự làm phiền bạn là đây :

nhập mô tả hình ảnh ở đây

Việc lạm dụng UML nhỏ dễ thương này tương phản hướng phụ thuộc mã nguồn với hướng điều khiển. Đây là nơi câu trả lời cho câu hỏi của bạn có thể được tìm thấy.

Trong mối quan hệ sử dụng:

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

luồng điều khiển đi theo cùng hướng mà phụ thuộc mã nguồn thực hiện.

Trong một mối quan hệ thực hiện:

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

luồng điều khiển thường đi theo hướng ngược lại, sự phụ thuộc mã nguồn thực hiện.

Điều đó có nghĩa là bạn đang thực sự nhìn vào điều này:

nhập mô tả hình ảnh ở đây

Bạn sẽ có thể thấy rằng luồng điều khiển sẽ không bao giờ có được từ Người thuyết trình đến Chế độ xem.

Làm thế nào mà có thể được? Nó có nghĩa là gì?

Điều đó có nghĩa là chế độ xem có luồng riêng của nó (không phải là bất thường) hoặc (như @Euphoric chỉ ra) luồng kiểm soát đang đi vào chế độ xem từ một thứ khác không được mô tả ở đây.

Nếu đó là cùng một chủ đề thì Chế độ xem sẽ biết khi nào Mô hình xem sẵn sàng để đọc. Nhưng nếu đó là trường hợp và khung nhìn là GUI thì sẽ khó có thể sơn lại màn hình khi người dùng di chuyển xung quanh trong khi họ chờ DB.

Nếu khung nhìn có luồng riêng thì nó có luồng điều khiển riêng. Điều đó có nghĩa là để thực hiện điều này, Chế độ xem sẽ phải thăm dò Mô hình Chế độ để nhận thấy các thay đổi.

Vì Người thuyết trình không biết Chế độ xem tồn tại và Chế độ xem không biết Người thuyết trình tồn tại nên họ không thể gọi nhau. Họ không thể ném các sự kiện vào nhau. Tất cả những gì có thể xảy ra là Người thuyết trình sẽ ghi vào Mô hình xem và Chế độ xem sẽ đọc Mô hình xem. Bất cứ khi nào nó cảm thấy thích nó.

Theo sơ đồ này, điều duy nhất mà Chế độ xem và Người trình bày chia sẻ là kiến ​​thức về Mô hình Chế độ xem. Và nó chỉ là một cấu trúc dữ liệu. Vì vậy, đừng hy vọng nó có bất kỳ hành vi nào.

Điều đó có vẻ không thể nhưng nó có thể được thực hiện để hoạt động ngay cả khi Mô hình xem phức tạp. Một trường cập nhật nhỏ là tất cả các chế độ xem sẽ phải thăm dò để phát hiện thay đổi.

Bây giờ tất nhiên bạn có thể khăng khăng sử dụng mẫu người quan sát hoặc có một số điều cơ bản che giấu vấn đề này với bạn nhưng xin vui lòng hiểu rằng bạn không phải làm vậy.

Đây là một chút thú vị tôi đã minh họa dòng kiểm soát:

nhập mô tả hình ảnh ở đây

Lưu ý rằng bất cứ khi nào bạn thấy luồng đi ngược lại các hướng tôi đã xác định trước đó, điều bạn đang thấy là một cuộc gọi trở lại. Thủ thuật đó sẽ không giúp chúng ta đến được View. Chà, trừ khi trước tiên chúng ta trở lại bất cứ thứ gì gọi là Bộ điều khiển. Hoặc bạn chỉ có thể thay đổi thiết kế để bạn có thể xem. Điều đó cũng khắc phục sự cố giống như bắt đầu của sự cố yo-yo với Truy cập dữ liệu và Giao diện.

Điều duy nhất khác để tìm hiểu ở đây ngoài đó là Bộ xử lý trường hợp sử dụng có thể gọi khá nhiều thứ theo bất kỳ thứ tự nào nó muốn miễn là nó gọi cho người trình bày trước.


Cảm ơn rất nhiều vì đã trả lời, tôi đã thấy câu trả lời của bạn cho nhiều câu hỏi khác về Kiến trúc sạch. Bạn có gợi ý rằng Chế độ xem liên tục kiểm tra cờ, ví dụ, trong Mô hình Chế độ xem để xem có bất kỳ thay đổi nào không? Sau đó, chế độ xem có phải hiển thị lại toàn bộ Mô hình Chế độ xem hay tôi nên sử dụng một bộ cờ lồng nhau để cho biết dữ liệu nào đã được thay đổi?
Fearnbuster

Quan điểm không phải thăm dò ý kiến ​​liên tục. Ví dụ: web 1.0 chỉ thăm dò ý kiến ​​khi người dùng nhấn tải lại. Bỏ phiếu liên tục là một quyết định thiết kế nên xem xét nhu cầu thực sự của người dùng. Tôi chỉ nói rằng nó có thể. Điểm của trường cập nhật là giúp phát hiện cập nhật nhanh. Chỉ cần nếu Mô hình xem phức tạp. Cũng xem xét những gì xảy ra nếu chế độ xem đọc trong khi người trình bày đang ở giữa một bản cập nhật.
candied_orange

Được rồi, cảm ơn rất nhiều vì sự giúp đỡ. Nếu / khi bạn theo kiến ​​trúc này, đây có phải là kỹ thuật mà bạn thường sử dụng không?
Fearnbuster

1
Tôi nghĩ có một sai lầm lớn khi nhóm trả lời này kết hợp phụ thuộc thiết kế và phụ thuộc thời gian chạy. Hai có thể khác nhau.
Euphoric

1
@Euphoric Tại sao cảm ơn bạn. Tôi buộc chúng lại với nhau bởi vì nếu bạn không có sự phụ thuộc mã nguồn vào thứ gì đó thì bạn không thể sử dụng tham chiếu thời gian chạy cho bất cứ điều gì vì bạn không hiểu nó là gì. Tất cả những gì bạn có thể làm là giữ tham chiếu giống như một bộ sưu tập. Nếu đó là một sai lầm tôi muốn hiểu nó.
candied_orange

2

Tôi thấy vấn đề này quá khó hiểu và sẽ mất rất nhiều văn bản và thời gian để giải thích chính xác vấn đề vì tôi tin rằng bạn hiểu nhầm cả Kiến trúc sạch và MVVM của Martin.

Điều đầu tiên cần lưu ý là sơ đồ bạn đã đăng không đầy đủ. Nó chỉ hiển thị "logic kinh doanh", nhưng thiếu một số loại "dàn nhạc" thực sự làm cho các bộ phận di chuyển theo đúng thứ tự. nhập mô tả hình ảnh ở đây

Mã của dàn nhạc sẽ đơn giản như

string Request(string request) // returns response
{
    Controller.Run(data);
    Presenter.Run();
    return View.Run();
}

Tôi tin rằng tôi đã nghe Martin nói về điều này trong một trong những cuộc nói chuyện của anh ấy về Kiến trúc sạch.

Một điều khác cần chỉ ra là nhận xét của candied_orange về việc thiếu chu kỳ là sai. Có, chu kỳ không tồn tại (và không nên) trong kiến ​​trúc của mã. Nhưng chu kỳ giữa các trường hợp thời gian chạy là phổ biến và thường dẫn đến thiết kế đơn giản hơn.

Đó là trường hợp trong MVVM. Trong Chế độ xem MVVM phụ thuộc vào ViewModel và ViewModel sử dụng các sự kiện để thông báo cho View về những thay đổi của nó. Điều này có nghĩa là trong thiết kế của các lớp, chỉ có sự phụ thuộc từ các lớp View đến Model, nhưng trong thời gian chạy, có sự phụ thuộc theo chu kỳ giữa các phiên bản View và ViewModel. Do đó, không cần người điều phối, vì ViewModel sẽ cung cấp cách Xem để tìm ra khi nào nên tự cập nhật. Đây là lý do tại sao "thông báo" trong sơ đồ này sử dụng dòng "squigly" chứ không phải dòng trực tiếp. Điều đó có nghĩa là View quan sát các thay đổi trong ViewModel, không phải ViewModel phụ thuộc vào View.

nhập mô tả hình ảnh ở đây

Điều quan trọng nhất bạn nên lấy từ Kiến trúc sạch của Martin không phải là bản thân thiết kế, mà là cách bạn xử lý các phụ thuộc. Một trong những điểm quan trọng mà anh ấy đưa ra trong các cuộc nói chuyện của mình là khi có một ranh giới, thì tất cả các phụ thuộc mã sẽ vượt qua ranh giới đó theo một hướng. Trong sơ đồ, ranh giới này được thể hiện bằng đường đôi. Và có rất nhiều phụ thuộc đảo thông qua giao diện ( InputBoundary, OutputBoundaryDataAccessInterface ) mà sửa theo hướng đang phụ thuộc.

Ngược lại, ViewModeltrong Kiến trúc sạch chỉ là DTO đơn giản không có logic. Điều này được thực hiện rõ ràng bằng <DS>thẻ. Và đây là lý do tại sao orchestratorcần thiết, nhưView sẽ không biết khi nào nên chạy logic.

Nếu tôi "làm phẳng" sơ đồ thành giao diện trong thời gian chạy, nó sẽ trông như thế này:

nhập mô tả hình ảnh ở đây

Vì vậy, trong thời gian chạy, các phụ thuộc theo hướng "sai", nhưng điều đó là tốt.

Tôi khuyên bạn nên xem bài nói chuyện của anh ấy về Kiến trúc sạch để hiểu rõ hơn lý lẽ của anh ấy.


"Dàn nhạc" của bạn không nên gọi Người thuyết trình. Use Case Interactor làm điều đó.
candied_orange

@candied_orange Đúng, đó là một sai lầm.
Euphoric

Cảm ơn câu trả lời, thật tốt khi nhận được một vài ý kiến ​​khác nhau. Tôi ủng hộ cả hai câu trả lời của các bạn. Có ai trong hai bạn tình cờ biết nếu Robert Martin có một cơ sở mã ở đâu đó mà anh ta đã triển khai một hình thức Kiến trúc của mình không? Tôi đã xem dự án FitNess của anh ấy, nhưng tôi không thể nhìn thấy rừng cây. Ngoài ra, tôi có đúng không khi suy đoán rằng, mặc dù hình ảnh tôi đăng là sơ đồ mà chú Bob luôn sử dụng trong các cuộc nói chuyện của mình, nhưng thực ra đây chỉ là một ví dụ về kiến ​​trúc của bạn CÓ THỂ trông như thế nào? Trong khi nó có thể trông rất khác nhau miễn là dòng phụ thuộc là chính xác?
Fearnbuster

@Fearnbuster Để câu hỏi cuối cùng của bạn, có. Hướng của sự phụ thuộc quan trọng hơn cấu trúc. Tôi tin rằng "Kiến trúc sạch", "Kiến trúc hành tây" và "Kiến trúc lục giác" thực sự là những triển khai của cùng một ý tưởng "Giữ sự phụ thuộc trong kiểm tra".
Euphoric

@Euphoric Thành thật mà nói, tôi có thể nói rằng đây có thể là trường hợp, bởi vì trong một hình ảnh khác của cuốn sách của anh ấy (Hình 8.2 của Chương 8), anh ấy cho thấy một kiến ​​trúc trông khác. Trong sơ đồ đó, Người điều khiển thực sự là người trung gian giữa Người giao dịch và Người trình bày. Cũng không có Ranh giới đầu ra cho Giao dịch viên; Dường như Interactor nhận được yêu cầu thông qua một giao diện, và sau đó trả về các phản hồi thông qua cùng một giao diện (Tôi giả sử điều này được thực hiện thông qua một giá trị trả về hàm đơn giản, vì tôi không thể nghĩ ra bất kỳ cơ chế nào khác sẽ hoạt động theo cách đó).
Fearnbuster
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.