Làm thế nào tốt nhất có thể tránh viết mã GUI cồng kềnh?


48

Tôi tìm thấy bất cứ khi nào tôi làm việc với mã GUI, mã có xu hướng nở nhanh hơn các loại mã khác. Nó cũng có vẻ khó hơn để tái cấu trúc. Trong khi ở các loại mã khác, tôi có thể cấu trúc lại khá dễ dàng - tôi thấy tôi có thể phân tách một lớp lớn hơn thành các phần chức năng nhỏ hơn - với hầu hết các khung GUI tôi thường bị ràng buộc với một khung công tác yêu cầu tiện ích / điều khiển / lớp của tôi thực hiện nhiều thứ trực tiếp hơn trong widget / control / anything. Đôi khi, điều này là do cần (a) kế thừa một số tiện ích / điều khiển / điều cơ sở hoặc (b) cần quyền truy cập vào các phương thức được bảo vệ.

Tôi thường cũng phải, ví dụ, phản ứng với nhiều loại đầu vào thông qua tín hiệu / sự kiện / bất cứ điều gì từ khung để thực hiện tất cả các chế độ tương tác với người dùng. Tôi có thể cần trong một tiện ích / điều khiển GUI để xử lý nhiều loại đầu vào / đầu ra có thể bao gồm:

  1. một nhấp chuột phải / menu ngữ cảnh
  2. phản ứng với các lựa chọn từ menu ngữ cảnh - có thể nhiều
  3. một cách đặc biệt để vẽ GUI
  4. phản ứng với đầu vào bàn phím
  5. nút, hộp kiểm,
  6. Vân vân

... Tất cả trong khi quản lý các lớp trong GUI đại diện cho logic nghiệp vụ.

Một GUI đơn giản chuyển tiếp có thể khiến mã của nó phát triển khá nhanh, ngay cả khi tách biệt logic logic và sử dụng MVC, tôi thấy mã GUI là một nam châm lớn để thay đổi.

Có cách nào để quản lý mã GUI theo cách lành mạnh và tránh để nó trở thành một cửa sổ bị hỏng không? Hoặc là một khối các trình xử lý sự kiện ngẫu nhiên / các phương thức được ghi đè thực sự là cách tốt nhất chúng ta có thể làm cho mã GUI?


4
Định nghĩa chính xác của bạn về "phình to" là gì?

Câu trả lời:


36

Điều cần nhớ về mã GUI là nó được điều khiển theo sự kiện và mã hướng sự kiện luôn có sự xuất hiện của một khối các trình xử lý sự kiện được tổ chức ngẫu nhiên. Nơi nó trở nên thực sự lộn xộn là khi bạn cố gắng đưa mã không theo sự kiện vào lớp. Chắc chắn, nó có vẻ ngoài cung cấp hỗ trợ cho các trình xử lý sự kiện và bạn có thể giữ cho các trình xử lý sự kiện của bạn đẹp và nhỏ, nhưng tất cả các mã hỗ trợ bổ sung đó trôi nổi làm cho nguồn GUI của bạn có vẻ cồng kềnh và lộn xộn.

Vì vậy, những gì bạn có thể làm về điều này, và làm thế nào bạn có thể làm cho mọi thứ dễ dàng hơn để tái cấu trúc? Chà, trước tiên tôi sẽ thay đổi định nghĩa tái cấu trúc của mình từ việc tôi làm trong dịp này sang việc tôi làm liên tục khi tôi viết mã. Tại sao? Bởi vì bạn muốn tái cấu trúc để cho phép bạn dễ dàng sửa đổi mã của mình hơn và không phải là cách khác. Tôi không chỉ đơn giản là yêu cầu bạn thay đổi ngữ nghĩa ở đây, mà thay vào đó, yêu cầu bạn thực hiện một chút trị liệu tinh thần để thấy mã của bạn khác đi.

Ba kỹ thuật tái cấu trúc mà tôi thấy tôi sử dụng phổ biến nhất là Đổi tên , Phương thức trích xuấtLớp trích xuất . Nếu tôi chưa bao giờ học một phép tái cấu trúc nào khác, ba thứ đó vẫn cho phép tôi giữ mã của mình sạch sẽ và có cấu trúc tốt, và từ nội dung câu hỏi của bạn, có vẻ như bạn có thể sẽ thấy mình sử dụng ba phép tái cấu trúc gần như liên tục trong để giữ cho mã GUI của bạn mỏng và sạch sẽ.

Bạn có thể có sự phân tách tốt nhất về GUI và logic nghiệp vụ trên thế giới và mã GUI có thể trông giống như một mã của tôi đã được kích nổ ở giữa nó. Lời khuyên của tôi là không nên có thêm một hoặc hai lớp để giúp bạn quản lý GUI đúng cách và điều này không nhất thiết phải là các lớp View của bạn nếu bạn đang áp dụng mẫu MVC - mặc dù bạn thường xuyên tìm thấy các lớp trung gian rất giống với quan điểm của bạn đến nỗi bạn sẽ thường cảm thấy muốn hợp nhất chúng để thuận tiện. Tôi cho rằng điều này là thực sự không hại khi thêm một lớp dành riêng cho GUI để quản lý tất cả logic hình ảnh, tuy nhiên bạn có thể muốn cân nhắc lợi ích và chi phí khi làm như vậy.

Lời khuyên của tôi do đó là:

  • Không làm gì trực tiếp đằng sau GUI của bạn ngoại trừ việc gọi và xác định cách GUI sẽ nối vào View (hoặc một lớp trung gian).
  • Đừng cố bấm còi mọi thứ liên quan đến một lớp - hoặc thậm chí một lớp duy nhất trên mỗi cửa sổ GUI - trừ khi bạn làm như vậy có ý nghĩa. Thay thế của bạn là tạo ra nhiều lớp nhỏ và dễ quản lý để quản lý logic GUI của bạn.
  • Khi các phương thức của bạn bắt đầu trông lớn hơn một chút so với 4-5 dòng mã, hãy kiểm tra xem điều này có cần thiết không và liệu có thể trích xuất một hoặc hai phương thức để bạn có thể giữ phương thức của mình không, ngay cả khi điều này có nghĩa là một lớp với nhiều phương pháp hơn.
  • Nếu các lớp của bạn bắt đầu trông thực sự lớn, hãy bắt đầu bằng cách loại bỏ TẤT CẢ các chức năng trùng lặp, sau đó xem liệu bạn có thể nhóm hợp lý các phương thức của mình để bạn có thể trích xuất một hoặc hai lớp khác không.
  • Hãy suy nghĩ về tái cấu trúc mỗi khi bạn viết một dòng mã. Nếu bạn nhận được một dòng mã để làm việc, hãy xem liệu bạn có thể cấu trúc lại nó để tránh trùng lặp chức năng hay để làm cho nó gọn hơn một chút mà không thay đổi hành vi.
  • Chấp nhận điều không thể tránh khỏi, rằng bạn sẽ luôn cảm thấy rằng phần này hay phần khác trong hệ thống của bạn sẽ bắt đầu cảm thấy hơi khó chịu, đặc biệt nếu bạn bỏ bê việc tái cấu trúc khi bạn đi. Ngay cả với một cơ sở mã được bao bọc kỹ lưỡng, bạn vẫn có thể cảm thấy như có nhiều việc bạn có thể làm. Đây là thực tế của việc viết phần mềm, rằng bạn sẽ thấy mình luôn cảm thấy rằng một cái gì đó có thể đã được thực hiện "tốt hơn", vì vậy bạn cần phải cân bằng giữa làm một công việc chuyên nghiệp và mạ vàng.
  • Chấp nhận rằng bạn càng cố gắng giữ mã của bạn, mã của bạn sẽ càng ít bị phồng lên.

3
+1 Dù muốn hay không, GUI sẽ đảm nhiệm hàng trăm thao tác chi tiết và điều đó có nghĩa là mã.
Patrick Hughes

Các nhà phát triển nên học cách sử dụng mã hóa theo sự kiện cho GUI.
David Gao

23

Tôi nghĩ rằng nhiều vấn đề bạn đang gặp phải có thể bắt nguồn từ một nguyên nhân đơn giản. Hầu hết các nhà phát triển không coi mã GUI như mã 'thực'. Tôi không có bằng chứng hay số liệu thống kê ở đây, chỉ là cảm giác ruột của tôi.

Có lẽ họ nghĩ rằng đó là " chỉ trình bày " và không quan trọng. " Không có logic kinh doanh ở đó ", họ nói, " tại sao đơn vị kiểm tra nó "? Họ cười khi bạn đề cập đến định hướng đối tượng và viết mã sạch. Họ thậm chí không TRY để làm cho mọi thứ tốt hơn. Không có cấu trúc để bắt đầu, họ chỉ cần tát một số mã và để nó bị thối khi những người khác thêm liên lạc của riêng họ theo thời gian. Một mớ hỗn độn đẹp, mã graffiti.

Mã GUI có những thách thức độc đáo do đó phải được đối xử khác biệt và tôn trọng. Nó cần tình yêu và các nhà phát triển muốn viết nó. Những cái sẽ giữ cho nó mỏng và cho nó cấu trúc tốt và các mẫu chính xác.


2
+1 để ám chỉ nhận thức về mã GUI được đối xử khác với mã không phải gui. Tôi đã mất số lần tôi nghe ai đó nói, "đừng bận tâm kiểm tra GUI vì nó không hiệu quả về mặt chi phí và bên cạnh đó rất khó thực hiện". Tôi thường dịch thành "Thật khó khăn và tôi quá lười để học cách làm điều đó!".
S.Robins

1
+1 Nơi tôi làm việc, chúng tôi thường không xem lại mã GUI - "đó chỉ là GUI, bỏ qua nó". Và tôi cũng có tội như bất kỳ ai. Điều kỳ lạ là trong các dự án cá nhân của tôi, tôi đã dành rất nhiều thời gian nếu cố gắng để có được mã GUI sạch đẹp. Đoán nó chỉ là một điều văn hóa.
HappyCat

8

Vì một số lý do, mã GUI tạo ra một điểm mù trong các nhà phát triển về việc phân tách các mối quan tâm. Có lẽ đó là vì tất cả các hướng dẫn gộp mọi thứ vào một lớp. Có lẽ đó là vì sự thể hiện vật lý làm cho mọi thứ dường như được kết hợp chặt chẽ hơn so với thực tế. Có lẽ đó là do các lớp học được xây dựng từ từ nên mọi người không nhận ra họ cần tái cấu trúc, giống như con ếch hoạt ngôn được đun sôi bằng cách từ từ tăng nhiệt.

Dù lý do là gì, giải pháp là làm cho các lớp học của bạn nhỏ hơn rất nhiều. Tôi làm điều này bằng cách liên tục tự hỏi bản thân liệu có thể đưa những gì tôi đang gõ vào một lớp riêng biệt không. Nếu có thể đưa vào một lớp khác, và tôi có thể nghĩ ra một cái tên hợp lý và đơn giản cho lớp đó, thì tôi sẽ làm điều đó.


6

Bạn có thể muốn xem mẫu Mẫu Trình bày / Chế độ xem thụ động. Ray Ryan đã có một cuộc nói chuyện tốt trên Google IO về các thực tiễn kiến ​​trúc tốt nhất cho GWT.

http://www.google.com/events/io/2009/simes/GoogleWebToolkitBestPractices.html

Thật dễ dàng để trừu tượng hóa các ý tưởng cho các khuôn khổ và ngôn ngữ khác. Lợi ích chính của MVP (theo ý kiến ​​của tôi) là khả năng kiểm tra đơn vị. Và bạn chỉ nhận được điều đó, nếu mã của bạn không bị cồng kềnh và không phải spaghetti (đánh giá bằng câu hỏi của bạn, đây là những gì bạn muốn). Nó hoạt động bằng cách giới thiệu một lớp logic xem được gọi là người trình bày. Chế độ xem thực tế được tách rời khỏi giao diện này thông qua giao diện (và do đó có thể dễ dàng bị chế giễu trong các thử nghiệm đơn vị). Bây giờ, vì lớp logic xem của bạn (người trình bày) được giải phóng khỏi phần bên trong của khung GUI cụ thể, bạn có thể tổ chức nó như mã thông thường và bạn không bị ràng buộc với hệ thống phân cấp kế thừa Swings. Lý tưởng nhất là bạn có thể chuyển đổi các cài đặt GUI trong các khung khác nhau miễn là chúng phù hợp với cùng một giao diện.


1
+1. MVP tập trung chính xác vào cách trích xuất logic GUI thành các lớp riêng biệt, thường khác hoàn toàn với những gì mọi người hiểu khi họ nói về MVC.
Doc Brown

5

Câu trả lời của tôi bao gồm bốn phần: cấu trúc, đơn giản, kiểm tra và cú pháp.

Ba điều đầu tiên thực sự khó thực hiện!

Cấu trúc có nghĩa là chú ý nhiều đến việc sử dụng số lượng mã ít nhất và số lượng khung, thư viện tối đa, v.v.

Đơn giản có nghĩa là giữ mọi thứ đơn giản từ thiết kế ban đầu đến thực hiện thực tế. Giữ điều hướng đơn giản, sử dụng các plugin đơn giản, giữ bố cục khá 'đơn giản' sẽ giúp ích ở đây. Giờ đây, chúng có thể được 'bán' cho khách hàng / người dùng có thể nhanh chóng nhìn thấy những lợi thế của các trang hoạt động trên pc, ipad, di động và các thiết bị khác.

Kiểm tra có nghĩa là bao gồm các công cụ kiểm tra trình duyệt (webrat và capybara xuất hiện trong công việc của tôi) giúp nắm bắt các vấn đề của trình duyệt trước khi mã tốt hơn có thể được thiết kế để xử lý chúng ngay từ đầu, trái ngược với việc 'vá' mã thường xuyên bởi các nhà phát triển khác nhau khi họ được 'phát hiện' bởi người dùng của các trình duyệt khác nhau.

Cú pháp. Thật sự hữu ích khi sử dụng trình kiểm tra mã / IDE / trình soạn thảo-plugin, v.v. cho HTML, CSS, Javascript, v.v. nó, vì vậy một công cụ kiểm tra định dạng HTML của bạn là điều cần thiết. Có HTML được hình thành tốt sẽ rất hữu ích trong việc có HTML không bị lỗi vì mã xấu sẽ có nhiều khả năng hiển thị hơn.


4

Giải pháp tôi tìm thấy là mã khai báo. Chỉ sử dụng mã thủ tục là một công thức cho mã GUI spaghetti. Chắc chắn, một "cách đặc biệt để vẽ widget" có lẽ sẽ vẫn là mã. Nhưng đây là mã bị cô lập trong một lớp. Trình xử lý sự kiện, phím tắt, kích thước cửa sổ - tất cả những thứ lộn xộn được khai báo tốt nhất.


4

Có rất nhiều câu trả lời tuyệt vời ở đây.

Một điều đã giúp tôi đơn giản hóa mã GUI là đảm bảo rằng GUI có mô hình dữ liệu riêng.

Lấy một ví dụ đơn giản, nếu tôi có GUI có 4 trường nhập văn bản, thì tôi có một lớp dữ liệu riêng giữ nội dung của 4 trường nhập văn bản đó. GUI phức tạp hơn đòi hỏi nhiều lớp dữ liệu hơn.

Tôi thiết kế GUI như một mô hình - xem. Mô hình GUI được điều khiển bởi bộ điều khiển ứng dụng của mô hình ứng dụng - khung nhìn - bộ điều khiển. Khung nhìn ứng dụng là mô hình GUI, chứ không phải là mã GUI.


2

Các ứng dụng như Xử lý văn bản, Trình soạn thảo đồ họa, v.v. có giao diện phức tạp và mã của chúng không thể đơn giản. Tuy nhiên, đối với các ứng dụng kinh doanh, GUI không cần phải quá phức tạp nhưng một số vẫn như vậy.

Một số chìa khóa để đơn giản hóa GUI là (hầu hết áp dụng cho .NET):

  1. Phấn đấu cho thiết kế đơn giản hơn bất cứ khi nào có thể. Tránh các hành vi ưa thích nếu không được doanh nghiệp kêu gọi.

  2. Sử dụng một nhà cung cấp kiểm soát tốt.

  3. Đừng tạo chức năng kiểm soát tùy chỉnh trong chính mã máy khách. Thay vào đó, hãy tạo các điều khiển người dùng mở rộng điều khiển ban đầu theo cách mà bạn có thể phản ánh các hành vi cụ thể của mình trong các điều khiển thay vì theo mã của biểu mẫu / trang sử dụng.

  4. Sử dụng một khung (thậm chí là nhà được trồng) để xử lý quốc tế hóa, quản lý tài nguyên, kiểu dáng, v.v. để bạn không lặp lại mã này trong mọi UI.

  5. Sử dụng một thành phần (hoặc khung) để điều hướng.

  6. Xây dựng các hộp thoại tiêu chuẩn cho các lỗi, cảnh báo, xác nhận, v.v.


1

Áp dụng Thiết kế hướng đối tượng cho mã của bạn và để phát triển UI:

  1. Trình bày và mô hình riêng biệt Sử dụng thư viện / khung công tác MV-bất cứ thứ gì, hoặc viết riêng của bạn, để giúp tách biệt logic xem / điều khiển khỏi mô hình dữ liệu. Tất cả giao tiếp với phụ trợ phải được thực hiện bên trong mô hình và trạng thái mô hình phải luôn đồng bộ với phụ trợ.
  2. Decoupling Nếu đối tượng A biết về đối tượng B, thì A có thể gọi các phương thức trên B, nhưng B không nên biết về A. Thay vào đó A có thể lắng nghe các sự kiện từ B. Nó đảm bảo không có sự phụ thuộc vòng tròn. Nếu ứng dụng của bạn có nhiều sự kiện giữa các thành phần, thì hãy tạo EventBus hoặc tận dụng khung theo hướng sự kiện như Chuyến bay Twitter.
  3. Một phần so với kết xuất hoàn chỉnh Nếu chế độ xem của bạn là một bảng hoặc danh sách các mục, bạn có thể muốn tạo các phương thức như "thêm", "xóa" để chèn / xóa một mục vào / từ bộ sưu tập. Mã của bạn có thể dễ dàng bị phồng lên khi bạn phải hỗ trợ sắp xếp và phân trang. Vì vậy, lời khuyên của tôi là: chỉ cần hiển thị lại toàn bộ chế độ xem ngay cả khi có thay đổi một phần. Hiệu suất thì sao? tốt nếu bộ sưu tập của bạn lớn, thì dù sao bạn cũng nên phân trang. Nhà phát triển web: đảm bảo các trình xử lý sự kiện của bạn được ủy quyền cho phần tử gốc của khung nhìn không thay đổi.
  4. Mô hình chế độ xem Khi trạng thái chế độ xem của bạn trở nên quá phức tạp để duy trì, ví dụ, chế độ xem Bảng phải theo dõi dữ liệu hàng, dữ liệu cột, thứ tự sắp xếp, các hàng hiện được kiểm tra (nếu nó hỗ trợ đa kiểm tra), v.v., có lẽ bạn nên tạo một đối tượng ViewModel cho các trạng thái đó. Đối tượng View của bạn sẽ gọi setters trên ViewModel nếu có gì đó thay đổi trên UI (ví dụ: người dùng kiểm tra một hàng); và nó sẽ đáp ứng với sự kiện thay đổi của ViewModel bằng cách cập nhật giao diện người dùng. Thông thường, bạn nên tránh cập nhật UI nếu sự kiện thay đổi được kích hoạt bởi UI.

Đây là một ứng dụng nhỏ nhưng không tầm thường để giúp minh họa một số điểm của tôi. Bạn có thể tìm thấy mã và chế độ xem / sơ đồ tương tác mô hình tại đây: https://github.com/vanfrankie/pushpopbox


0

Bạn muốn xem qua khái niệm "databinding" . Đây là cách kết nối các phần tử UI với các phần tử mô hình trừu tượng theo cách khai báo sao cho các phần tử mô hình được tự động đồng bộ hóa với nội dung của UI. Có nhiều lợi ích của phương pháp này, ví dụ như không phải tự viết trình xử lý sự kiện để đồng bộ hóa dữ liệu.

Có hỗ trợ cơ sở dữ liệu cho nhiều khung công tác UI, ví dụ .NETEclipse / JFace .

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.