2010-03-24 81 views
14

OK Tôi có 2 lớp học thực sự lớn> 1k dòng mỗi lớp mà tôi hiện đã chia thành nhiều lớp. Sau đó, họ được tái kết hợp bằng cách sử dụng nhiều thừa kế. Bây giờ tôi tự hỏi, nếu có bất kỳ cách làm sạch hơn/tốt hơn để làm điều này. Hoàn toàn bao thanh toán chúng ra sẽ dẫn đến số lượng vô tận của các cuộc gọi self.otherself.do_something, mà tôi không nghĩ là cách nó nên được thực hiện.Thiết kế lớp học Python - Chia lớp lớn thành nhiều lớp thành các chức năng nhóm

Để làm cho mọi việc rõ ràng đây là những gì nó hiện trông giống như:

from gui_events import GUIEvents # event handlers 
from gui_helpers import GUIHelpers # helper methods that don't directly modify the GUI 

# GUI.py 
class GUI(gtk.Window, GUIEvents, GUIHelpers): 
    # general stuff here stuff here 

Một vấn đề đó là kết quả của việc này là pylint phàn nàn cho tôi hàng nghìn tỷ "init không được gọi là"/"thuộc tính không xác định"/"thuộc tính truy cập trước khi định nghĩa "cảnh báo.

CHỈNH SỬA:
Bạn có thể muốn xem mã, để tạo cho mình một bức tranh về toàn bộ thực tế.
http://github.com/BonsaiDen/Atarashii/tree/next/atarashii/usr/share/pyshared/atarashii/

Xin lưu ý, tôi thực sự cố gắng để giữ điều này càng tốt, tôi đang sử dụng thông tin để phát hiện trùng lặp mã, điều duy nhất nó phàn nàn là nhập.

+0

Đã xảy ra sự cố. Câu hỏi cho biết "> 1k dòng mỗi". Mã thực tế trong kho lưu trữ là 356 dòng. Vui lòng sửa câu hỏi hoặc liên kết. –

+0

Bạn cần tổng hợp: http://github.com/BonsaiDen/Atarashii/blob/next/atarashii/usr/share/pyshared/atarashii/gui.py http://github.com/BonsaiDen/Atarashii/blob/ tiếp theo/atarashii/usr/share/pyshared/atarashii/gui_events.py và http://github.com/BonsaiDen/Atarashii/blob/next/atarashii/usr/share/pyshared/atarashii/gui_helpers.py vì tôi đã chia công cụ lên (hiện tại chỉ có 968 dòng, bởi vì gần đây tôi đã chuyển một số công cụ sang các tệp khác). Ngoài ra, hãy xem các tệp * chế độ xem có cùng các dòng 1,1k. –

Trả lời

6

Nếu bạn muốn sử dụng nhiều thừa kế để kết hợp mọi thứ vào một lớp lớn (có thể làm điều này), thì bạn có thể cấu trúc lại từng lớp cha để mọi phương thức và thuộc tính riêng tư (bắt đầu bằng ' __ ') hoặc có tiền tố 2-3 ký tự ngắn duy nhất cho lớp đó. Ví dụ: tất cả các phương thức và thuộc tính trong lớp GUIEvents của bạn có thể bắt đầu bằng ge_, mọi thứ trong GUIHelpers có thể bắt đầu bằng gh_. Bằng cách này, bạn sẽ đạt được một số sự rõ ràng của việc sử dụng các cá thể lớp phụ riêng lẻ (self.ge.doSomething() vs self.ge_doSomething()) và bạn sẽ tránh xung đột tên thành viên, đây là rủi ro chính khi kết hợp các lớp lớn thành một.

+0

Tôi đoán đó là cách tôi sẽ tới đây, vì 1. nó dễ thực hiện với tìm kiếm/thay thế, 2. nó sẽ làm giảm cơ hội xung đột, tôi cũng sẽ có thể sử dụng nhiều tên chung chung hơn như um_get_items, thay vào đó của (update_messages) .get_messages và 3. như bạn đã nói nó sẽ mang lại sự rõ ràng vào mã và hiển thị nơi các phương thức có nguồn gốc của chúng. Tất cả trong tất cả nó khá đơn giản, có lẽ tôi đang suy nghĩ một chút để phức tạp sau khi dành 5 tuần lập trình điều này: D –

1

Tôi nghĩ đây là vấn đề về thiết kế OO chung hơn là vấn đề về Python. Python khá nhiều cung cấp cho bạn tất cả các công cụ OOP cổ điển, được đóng gói thuận tiện. Bạn sẽ phải mô tả vấn đề chi tiết hơn (ví dụ: các lớp học GUIEventsGUIHelpers có chứa gì?)

Một khía cạnh cụ thể của Python cần xem xét như sau: Python hỗ trợ nhiều mô hình lập trình và thường là giải pháp tốt nhất không OOP. Đây là có thể là trường hợp ở đây. Nhưng một lần nữa, bạn sẽ phải ném thêm chi tiết để có được một câu trả lời có ý nghĩa.

+0

Bạn có thể xem các lớp học tại đây: http://github.com/BonsaiDen/Atarashii/tree/next/atarashii/usr/share/pyshared/atarashii/ GUIEvents chủ yếu là về xử lý nội dung khi người dùng nhấp vào nút. GUIHelpers thiết lập một số công cụ nhỏ hơn như nhãn và những thứ khác, và cũng cung cấp một số chức năng tiện ích như is_ready. Tôi vẫn chưa hoàn thành việc quyết định phương thức nào thuộc về từng "lớp con". –

0

Mã của bạn có thể được cải thiện đáng kể bằng cách triển khai thiết kế Model-View-Controller. Tùy thuộc vào cách GUI và công cụ của bạn được thiết lập, bạn cũng có thể hưởng lợi từ việc "widget hóa" các phần của GUI, để thay vì có một Model-View-Controller khổng lồ, bạn có một Model-View-Controller chính quản lý một loạt các Các Model-View-Controllers nhỏ hơn, mỗi phần cho các phần riêng biệt của GUI của bạn. Điều này sẽ cho phép bạn chia nhỏ công cụ và GUI thành nhiều lớp và bạn có thể sử dụng lại các phần của nó, giảm tổng số mã bạn cần duy trì.

Trong khi python hỗ trợ nhiều mô hình lập trình, cho các công cụ GUI, giải pháp tốt nhất sẽ gần như luôn luôn là một thiết kế hướng đối tượng.

+0

Vấn đề là hiện tại tôi không thấy cách nào để giảm toàn bộ hơn nữa, Dialogs/TrayIcon và HTMLViews đã có trong các lớp riêng của họ, vì vậy điều GUI lớn này hiện chỉ quản lý các liên kết giữa những thứ đó và thanh trạng thái. Ngoài ra tôi đã DRYed mã cho cái chết ... điều duy nhất tôi có thể hình ảnh là chia GUI thành một thành phần mà thực sự sửa đổi công cụ có thể nhìn thấy và một trong những chỉ xử lý các sự kiện và như vậy, nhưng điều đó sẽ dẫn đến self.otherself. cuộc gọi foo:/ –

5

Bắt đầu bằng cách tìm các lớp học mô hình khái niệm thế giới thực mà ứng dụng của bạn cần làm việc. Đó là những ứng cử viên tự nhiên cho các lớp học.

Cố gắng tránh nhiều thừa kế càng nhiều càng tốt; nó hiếm khi hữu ích và luôn luôn hơi khó hiểu. Thay vào đó, hãy xem sử dụng thành phần chức năng (mối quan hệ "HAS-A") để cung cấp các thuộc tính phong phú cho các đối tượng của bạn được tạo từ các đối tượng khác.

Hãy nhớ đặt từng phương thức làm một điều nhỏ, cụ thể; điều này nhất thiết đòi hỏi phải phá vỡ các phương pháp làm quá nhiều thứ thành các phần nhỏ hơn.

Refactor trường hợp bạn tìm thấy nhiều phương pháp như vậy đang nhân bản chức năng của nhau; đây là một cách khác để tìm các bộ sưu tập tự nhiên về chức năng xứng đáng nằm trong một lớp riêng biệt.

+1

+1: "2 lớp học thực sự lớn> 1k dòng" Ouch. Điều đó rõ ràng bỏ lỡ quan điểm của thiết kế OO. Tất cả các trình xử lý sự kiện trong một lớp rõ ràng là sai. Người trợ giúp sự kiện không phải là thiết kế lớp học. –

0

Một khả năng là để gán chức năng nhập khẩu vào lớp thuộc tính:

Trong file a_part_1.py:

def add(self, n): 
    self.n += n 
def __init__(self, n): 
    self.n = n 

Và trong tập tin lớp học chính:

import a_part_1 

class A: 
    __init__ = a_part_1.__init__ 
    add = a_part_1.add 

Hoặc nếu bạn không muốn để cập nhật tệp chính khi các phương thức mới được thêm vào:

class A: pass 

import a_part_1 
for k, v in a_part_1.__dict__.items(): 
    if callable(v): 
     setattr(A,k,v) 
Các vấn đề liên quan