Tôi có thể coi nó là một mùi mã hoặc thậm chí là một mô hình chống để có một lớp thực hiện 23 giao diện. Nếu nó thực sự là một mô hình chống, bạn sẽ gọi nó là gì? Hay chỉ đơn giản là không tuân theo nguyên tắc trách nhiệm duy nhất?
Tôi có thể coi nó là một mùi mã hoặc thậm chí là một mô hình chống để có một lớp thực hiện 23 giao diện. Nếu nó thực sự là một mô hình chống, bạn sẽ gọi nó là gì? Hay chỉ đơn giản là không tuân theo nguyên tắc trách nhiệm duy nhất?
Câu trả lời:
Hoàng gia: Họ không làm bất cứ điều gì đặc biệt điên rồ nhưng họ có một tỷ danh hiệu và có liên quan đến hầu hết các hoàng gia khác bằng cách nào đó.
somehow
Tôi gửi rằng mẫu chống này được đặt tên là Jack of All Trades, hoặc có lẽ là quá nhiều mũ.
Nếu tôi phải đặt tên cho nó, tôi nghĩ tôi sẽ gọi nó là Hydra :
Trong thần thoại Hy Lạp, Lernaean Hydra (tiếng Hy Lạp: Λερί α) là một con thú nước chthonic giống như con rắn cổ đại, với những đặc điểm của loài bò sát, (như tên gọi của nó) có nhiều đầu - các nhà thơ đề cập đến nhiều đầu hơn sơn, và với mỗi cái đầu bị cắt, nó lại mọc thêm hai lần nữa - và hơi thở độc đến nỗi độc tính ngay cả dấu vết của cô cũng chết người.
Liên quan đặc biệt là thực tế là nó không chỉ có nhiều đầu, mà còn phát triển ngày càng nhiều trong số chúng và không thể bị giết vì nó. Đó là kinh nghiệm của tôi với những kiểu thiết kế này; Các nhà phát triển cứ tiếp tục gây nhiễu ngày càng nhiều giao diện vào nó cho đến khi nó có quá nhiều màn hình vừa vặn, và sau đó nó trở nên quá cố chấp trong thiết kế của chương trình và giả định rằng việc tách nó ra là một viễn cảnh vô vọng (nếu bạn thử, bạn thực sự sẽ thường kết thúc cần nhiều giao diện hơn để thu hẹp khoảng cách).
Một dấu hiệu ban đầu của sự diệt vong sắp xảy ra do "Hydra" là thường xuyên chuyển giao diện này sang giao diện khác, mà không cần kiểm tra nhiều và thường xuyên đến một mục tiêu vô nghĩa, như trong:
public void CreateWidget(IPartLocator locator, int widgetTypeId)
{
var partsNeeded = locator.GetPartsForWidget(widgetTypeId);
return ((IAssembler)locator).BuildWidget(partsNeeded);
}
Rõ ràng là khi được đưa ra khỏi bối cảnh có một cái gì đó đáng nghi về mã này, nhưng khả năng điều này xảy ra sẽ tăng lên khi có nhiều "đầu" hơn, bởi vì các nhà phát triển trực giác biết rằng họ luôn đối phó với cùng một sinh vật.
Chúc may mắn khi thực hiện bất kỳ bảo trì trên một đối tượng thực hiện 23 giao diện. Cơ hội bạn không gây ra thiệt hại tài sản thế chấp trong quá trình là không có gì.
Các Thiên Chúa đối tượng nói đến cái tâm; một đối tượng duy nhất biết cách làm MỌI THỨ. Điều này xuất phát từ việc tuân thủ thấp các yêu cầu "gắn kết" của hai phương pháp thiết kế chính; nếu bạn có một đối tượng với 23 giao diện, bạn có một đối tượng biết cách tạo ra 23 thứ khác nhau cho người dùng của nó và 23 thứ khác nhau đó có thể không nằm dọc theo một dòng của một nhiệm vụ hoặc khu vực của hệ thống.
Trong RẮN, trong khi người tạo ra đối tượng này rõ ràng đã cố gắng tuân theo Nguyên tắc phân chia giao diện, họ đã vi phạm quy tắc trước đó; Nguyên tắc trách nhiệm duy nhất. Có một lý do đó là "RẮN"; S luôn đến đầu tiên khi nghĩ về thiết kế, và tất cả các quy tắc khác tuân theo.
Trong GRASP, người tạo ra một lớp như vậy đã bỏ qua quy tắc "Độ gắn kết cao"; GRASP, không giống như RẮN, dạy rằng một đối tượng KHÔNG CÓ trách nhiệm duy nhất, nhưng nhiều nhất nó phải có hai hoặc ba trách nhiệm liên quan rất chặt chẽ.
23 chỉ là một con số! Trong trường hợp rất có thể, nó đủ cao để báo động. Tuy nhiên, nếu chúng ta hỏi, số phương thức / giao diện cao nhất là bao nhiêu trước khi nó có thể nhận được một thẻ được gọi là "chống mẫu"? Là 5 hay 10 hay 25? Bạn nhận ra rằng con số đó thực sự không phải là một câu trả lời bởi vì nếu 10 là tốt, thì 11 cũng có thể - và sau đó là bất kỳ số nguyên nào sau đó.
Câu hỏi thực sự là về sự phức tạp. Và chúng ta nên chỉ ra rằng mã dài, số phương thức hoặc kích thước lớn của lớp bằng bất kỳ biện pháp nào thực sự KHÔNG phải là định nghĩa về độ phức tạp. Có, mã lớn hơn và lớn hơn (số lượng phương thức lớn hơn) sẽ gây khó khăn cho việc đọc và nắm bắt cho người mới bắt đầu. Nó cũng xử lý các chức năng có khả năng đa dạng, số lượng lớn các trường hợp ngoại lệ và các thuật toán khá phát triển cho các tình huống khác nhau. Điều này không có nghĩa là nó phức tạp - nó chỉ khó tiêu hóa.
Mặt khác, mã kích thước tương đối nhỏ mà người ta có thể hy vọng đọc được trong vài giờ vào và ra - vẫn có thể phức tạp. Đây là khi tôi nghĩ rằng mã là (không cần thiết) phức tạp.
Mọi trí tuệ của thiết kế hướng đối tượng có thể được đưa vào đây để định nghĩa "phức tạp" nhưng tôi sẽ hạn chế ở đây để hiển thị khi "rất nhiều phương thức" là một dấu hiệu của sự phức tạp.
Kiến thức lẫn nhau. (còn gọi là khớp nối) Nhiều khi mọi thứ được viết dưới dạng các lớp, tất cả chúng ta đều nghĩ rằng đó là mã hướng đối tượng "đẹp". Nhưng giả định về lớp khác về cơ bản phá vỡ sự đóng gói thực sự cần thiết. Khi bạn có các phương thức "rò rỉ" chi tiết sâu về trạng thái bên trong của các thuật toán - và ứng dụng được xây dựng với giả định chính về trạng thái bên trong của lớp phục vụ.
Quá nhiều lần lặp lại (đột nhập) Khi các phương thức có tên tương tự nhưng thực hiện công việc mâu thuẫn - hoặc mâu thuẫn với các tên có chức năng tương tự. Nhiều lần mã phát triển để hỗ trợ các giao diện hơi khác nhau cho các ứng dụng khác nhau.
Quá nhiều vai trò Khi lớp tiếp tục thêm các chức năng phụ và tiếp tục mở rộng hơn khi mọi người thích nó, chỉ để biết rằng lớp thực sự bây giờ là một lớp. Đáng ngạc nhiên là tất cả bắt đầu với chính hãngyêu cầu và không có lớp khác tồn tại để làm điều này. Hãy xem xét điều này, có một Giao dịch lớp, cho biết chi tiết về giao dịch. Có vẻ tốt cho đến nay, bây giờ ai đó yêu cầu chuyển đổi định dạng vào "thời gian giao dịch" (giữa UTC và tương tự), sau này, mọi người thêm quy tắc để kiểm tra xem một số thứ nhất định vào một số ngày nhất định để xác thực các giao dịch không hợp lệ. - Tôi sẽ không viết toàn bộ câu chuyện nhưng cuối cùng, lớp giao dịch xây dựng toàn bộ lịch trong đó và sau đó mọi người bắt đầu sử dụng phần "chỉ lịch" của nó! Điều này rất phức tạp (để tưởng tượng) tại sao tôi sẽ khởi tạo "lớp giao dịch" để có chức năng mà "lịch" sẽ cung cấp cho tôi!
(Trong) tính nhất quán của API Khi tôi làm book_a_ticket () - Tôi đặt vé! Điều đó rất đơn giản bất kể có bao nhiêu kiểm tra và quy trình để thực hiện. Bây giờ nó trở nên phức tạp khi dòng thời gian bắt đầu ảnh hưởng đến điều này. Thông thường, người ta sẽ cho phép "tìm kiếm" và trạng thái khả dụng / không khả dụng, sau đó để giảm thời gian quay lại, bạn bắt đầu lưu một số gợi ý ngữ cảnh bên trong vé và sau đó tham khảo để đặt vé. Tìm kiếm không phải là chức năng duy nhất - mọi thứ trở nên tồi tệ hơn sau nhiều "chức năng phụ" như vậy. Trong quá trình, ý nghĩa của book_a_ticket () ngụ ý book_that_ticket ()! và điều đó có thể phức tạp không thể tưởng tượng được.
Có thể có nhiều tình huống như vậy bạn sẽ thấy trong một mã rất phát triển và tôi chắc chắn rằng nhiều người có thể thêm các kịch bản, trong đó "rất nhiều phương pháp" chỉ không có ý nghĩa hoặc không làm những gì bạn rõ ràng sẽ nghĩ. Đây là mô hình chống.
Kinh nghiệm cá nhân của tôi là khi các dự án bắt đầu từ dưới lên một cách hợp lý , nhiều thứ đáng lẽ phải có các lớp chính hãng tự mình bị chôn vùi hoặc tệ hơn vẫn bị phân chia giữa các lớp khác nhau và tăng khớp nối. Hầu hết những gì có thể xứng đáng với 10 lớp, nhưng chỉ có 4 lớp, có khả năng nhiều trong số chúng có nhiều mục đích khó hiểu và số lượng lớn các phương thức. Gọi nó là THIÊN CHÚA và DRAGON, đây là BAD.
NHƯNG bạn bắt gặp các lớp RẤT LỚN nhất quán, chúng có 30 phương thức - và vẫn rất SẠCH. Họ có thể tốt.
Các lớp nên có chính xác số lượng giao diện chính xác; không nhiều không ít.
Nói "quá nhiều" sẽ là không thể nếu không xem liệu tất cả các giao diện đó có phục vụ mục đích hữu ích trong lớp đó hay không. Khai báo rằng một đối tượng thực hiện một giao diện có nghĩa là bạn phải thực hiện các phương thức của nó nếu bạn muốn lớp biên dịch. (Tôi đoán rằng lớp bạn đang xem.) Nếu mọi thứ trong giao diện được triển khai và các triển khai đó làm một cái gì đó liên quan đến các bộ phận của lớp, thật khó để nói rằng việc triển khai không nên ở đó. Trường hợp duy nhất tôi có thể nghĩ về nơi một giao diện đáp ứng các tiêu chí đó sẽ không thuộc về bên ngoài: khi không ai sử dụng nó.
Một số ngôn ngữ cho phép các giao diện được "phân lớp" bằng cách sử dụng một cơ chế như extends
từ khóa của Java và bất cứ ai đã viết nó có thể không biết điều đó. Cũng có thể là tất cả 23 đều đủ xa để tổng hợp chúng không có ý nghĩa.
Nghe có vẻ như họ có một cặp "getter" / "setter" cho mỗi thuộc tính, như bình thường đối với một "bean" điển hình và đã quảng bá tất cả các phương thức này lên giao diện. Vì vậy, làm thế nào về việc gọi nó là " có đậu ". Hoặc "đầy hơi" của Rabelaisian sau khi ảnh hưởng nổi tiếng của quá nhiều đậu.
Số lượng giao diện thường phát triển khi một đối tượng chung được sử dụng trong các môi trường khác nhau. Trong C #, các biến thể của IComparable, IEqualityComparer và IComparer cho phép sắp xếp theo các thiết lập riêng biệt, do đó bạn có thể sẽ thực hiện tất cả chúng, một số trong số chúng có thể nhiều hơn một lần vì bạn có thể thực hiện các phiên bản được gõ mạnh chung cũng như các phiên bản không chung chung , ngoài ra, bạn có thể thực hiện nhiều hơn một trong những khái quát.
Hãy lấy một kịch bản ví dụ, giả sử một webshop nơi bạn có thể mua các khoản tín dụng mà bạn có thể mua một thứ khác (các trang web ảnh chứng khoán thường sử dụng chương trình này). Bạn có thể có một lớp "Valuta" và một lớp "Tín dụng" kế thừa cùng một cơ sở. Valuta có một số quá tải toán tử tiện lợi và thói quen so sánh cho phép bạn thực hiện các phép tính mà không phải lo lắng về tài sản "Tiền tệ" (ví dụ như thêm bảng Anh vào đô la). Tín dụng được phân bổ đơn giản hơn nhưng có một số hành vi khác biệt. Muốn có thể so sánh chúng với nhau, cuối cùng bạn có thể triển khai IComparable cũng như IComparable và các biến thể khác của giao diện so sánh trên cả hai (mặc dù chúng sử dụng một triển khai chung cho dù đó là trong lớp cơ sở hay ở nơi nào khác).
Khi thực hiện tuần tự hóa, ISerializable, IDeserializationCallback được triển khai. Sau đó thực hiện ngăn xếp hoàn tác lại: IClonable được thêm vào. Chức năng IsDenty: IObservable, INotifyPropertyChanged. Cho phép người dùng chỉnh sửa các giá trị bằng chuỗi: IConvertable ... Danh sách có thể tiếp tục và bật ...
Trong các ngôn ngữ hiện đại, chúng ta thấy một xu hướng khác nhau giúp phân tách các khía cạnh này và đặt chúng trong các lớp riêng của chúng, bên ngoài lớp cốt lõi. Lớp bên ngoài hoặc khía cạnh sau đó được liên kết với lớp đích bằng cách sử dụng chú thích (thuộc tính). Thông thường có thể làm cho các lớp khía cạnh bên ngoài ít nhiều chung chung.
Việc sử dụng các thuộc tính (chú thích) có thể được phản ánh. Một nhược điểm là mất hiệu suất nhỏ (ban đầu). Một nhược điểm (thường là cảm xúc) là các nguyên tắc như đóng gói cần phải được thư giãn.
Luôn luôn có các giải pháp khác, nhưng đối với mọi giải pháp tiện lợi đều có sự đánh đổi hoặc nắm bắt. Ví dụ: sử dụng giải pháp ORM có thể yêu cầu tất cả các thuộc tính được khai báo ảo. Các giải pháp tuần tự hóa có thể yêu cầu các nhà xây dựng mặc định trên các lớp của bạn. Nếu bạn đang sử dụng phép nội xạ phụ thuộc, bạn có thể sẽ thực hiện 23 giao diện trên một lớp.
Trong mắt tôi, 23 giao diện không phải là xấu theo định nghĩa. Có thể có một kế hoạch được cân nhắc kỹ lưỡng đằng sau nó, hoặc một số xác định nguyên tắc như tránh sử dụng sự phản ánh hoặc niềm tin đóng gói cực đoan.
Bất cứ khi nào chuyển đổi một công việc, hoặc phải xây dựng trên một kiến trúc hiện có. Lời khuyên của tôi là trước tiên hãy làm quen hoàn toàn, đừng cố gắng cấu trúc lại mọi thứ quá nhanh. Lắng nghe nhà phát triển ban đầu (nếu anh ta vẫn ở đó) và cố gắng tìm ra những suy nghĩ và ý tưởng đằng sau những gì bạn nhìn thấy. Khi đặt câu hỏi, làm như vậy không phải vì mục đích phá vỡ nó, mà để tìm hiểu ... Vâng, mọi người đều có búa vàng của riêng mình, nhưng càng nhiều búa bạn có thể thu thập càng dễ dàng hơn với các đồng nghiệp.
"Quá nhiều" là chủ quan: phong cách lập trình? hiệu suất? sự phù hợp với tiêu chuẩn? tiền lệ? chỉ đơn giản là cảm giác thoải mái / tự tin?
Miễn là mã của bạn hoạt động đúng và không có vấn đề về khả năng bảo trì, 23 thậm chí có thể là chuẩn mực mới. Một ngày nào đó tôi có thể nói: "Bạn có thể thực hiện một tác phẩm xuất sắc với 23 giao diện, xem: Jonas Elfström".
Tôi sẽ nói rằng giới hạn phải là một số nhỏ hơn 23 - giống như 5 hoặc 7,
tuy nhiên, điều này không bao gồm bất kỳ số giao diện nào mà các giao diện đó kế thừa hoặc bất kỳ số giao diện nào được thực hiện bởi các lớp cơ sở.
(Vì vậy, hoàn toàn, N + bất kỳ số lượng giao diện được kế thừa, trong đó N <= 7.)
Nếu lớp của bạn thực hiện quá nhiều giao diện, nó có thể là một lớp thần .