Làm thế nào để có quá nhiều biến thể hiện dẫn đến mã trùng lặp?


19

Theo Tái cấu trúc các mẫu :

Khi một lớp đang cố gắng làm quá nhiều, nó thường hiển thị quá nhiều biến thể hiện. Khi một lớp có quá nhiều biến thể hiện, mã trùng lặp không thể bị bỏ lại phía sau.

Làm thế nào để có quá nhiều biến thể hiện dẫn đến mã trùng lặp?


2
Đơn giản chỉ cần đặt: nví dụ các biến boolean tạo một không gian trạng thái bên trong của 2^n. Thường xuyên hơn không phải mặc dù đối tượng của bạn không có nhiều trạng thái có thể quan sát được , nhưng vì bạn đã nhồi nhét tất cả trạng thái đó vào một đối tượng, nên trong nội bộ, bạn vẫn phải xử lý tất cả.
biziclop

Câu trả lời:


23

Có quá nhiều biến thể hiện không liên quan trực tiếp đến mã trùng lặp hoặc ngược lại. Tuyên bố này, trong khái quát này, là sai. Người ta có thể ném hai lớp riêng biệt không có mã trùng lặp vào một lớp - tạo ra một lớp mới với các trách nhiệm không tách rời và quá nhiều biến thể hiện, nhưng vẫn không có mã trùng lặp.

Nhưng khi bạn tìm thấy một lớp có quá nhiều phản hồi trong mã kế thừa trong thế giới thực, rất có thể lập trình viên đã viết nó không quan tâm đến mã sạch hoặc các nguyên tắc RẮN (ít nhất là tại thời điểm anh ta viết mã đó), vì vậy, đó là không có khả năng bạn sẽ tìm thấy mã khác có mùi giống như mã trùng lặp trong đó.

Ví dụ, mô hình chống tái sử dụng "sao chép-dán" thường được áp dụng bằng cách sao chép một phương thức cũ và thực hiện một số sửa đổi nhỏ cho nó, mà không cần tái cấu trúc đúng. Đôi khi, để làm cho công việc này, người ta phải nhân đôi một biến thành viên và sửa đổi biến đó một chút. Điều này có thể dẫn đến một lớp có quá nhiều biến thể hiện (chính xác hơn: quá nhiều biến đối tượng trông rất giống nhau). Trong tình huống như vậy, các biến đối tượng tương tự có thể là một chỉ báo cho mã lặp lại ở nơi khác trong lớp. Tuy nhiên, như bạn đã lưu ý, đây là một ví dụ nhân tạo và tôi sẽ không kết luận một quy tắc chung từ nó.


11

Quá nhiều biến thể hiện có nghĩa là quá nhiều trạng thái. Quá nhiều trạng thái dẫn đến mã trùng lặp chỉ khác nhau một chút cho mỗi trạng thái.

Đây là lớp bê tông đơn cổ điển làm quá nhiều thứ nên là lớp con hoặc tác phẩm.

Tìm một vài lớp có quá nhiều biến thể hiện, bạn sẽ thấy chúng duy trì trạng thái quá nhiều và có nhiều đường dẫn mã trùng lặp chỉ hơi chuyên biệt cho từng trường hợp, nhưng bị phá vỡ đến mức chúng không thể tách rời thành các phương thức có thể sử dụng lại. Đây là một trong những nguồn lớn nhất side effectslà tốt.

Có ít nhất một ngoại lệ cho điều này không thuộc loại này và là một cách dễ dàng để khắc phục điều này. Immutablecác đối tượng không có vấn đề này, vì chúng là một trạng thái cố định, không có bất kỳ cơ hội nào để quản lý trạng thái phức tạp hoặc tác dụng phụ.


7

Tuyên bố bạn trích dẫn có nghĩa là được nhìn thấy trong một bối cảnh cụ thể.

Theo kinh nghiệm của tôi, tôi không thể xác nhận rằng "nhiều biến thể hiện nói chung chỉ ra mã trùng lặp". Ngoài ra, lưu ý rằng điều này thuộc về "mùi mã", và có những mùi được cho là mâu thuẫn. Có một cái nhìn ở đây:

http://c2.com/cgi/wiki?CodeSmell

Thật thú vị, bạn sẽ thấy "quá nhiều biến đối tượng" có mùi mã tốt như "quá ít biến thể hiện".

Nhưng có vấn đề với các biến thể hiện, có thể là quá ít hoặc quá nhiều:

  1. Mỗi biến đối tượng có thể có nghĩa là một số loại trạng thái của đối tượng. Stati luôn cần một điều trị cẩn thận. Bạn phải đảm bảo rằng bạn đã bao gồm tất cả các kết hợp stati có thể để tránh hành vi bất ngờ. Bạn phải luôn luôn rõ ràng ngay bây giờ: đối tượng của tôi có trạng thái nào ngay bây giờ? Từ góc độ này, rất nhiều biến thể hiện có thể chỉ ra rằng lớp đã trở nên không thể xác định được. Nó cũng có thể chỉ ra rằng một lớp thực hiện quá nhiều công việc, vì nó cần rất nhiều stati.

  2. Mỗi biến đối tượng yêu cầu bạn phải giám sát, phương thức nào thay đổi biến theo cách nào. Vì vậy, đột nhiên, bạn không còn biết tất cả các đầu bếp đang nấu. Một trong số chúng, được lập trình một cách mệt mỏi vào đêm khuya, sẽ làm hỏng món súp của bạn. Một lần nữa: quá nhiều biến như vậy sẽ dẫn đến mã khó thâm nhập.

  3. Mặt khác: quá ít biến thể hiện có thể khiến nhiều phương thức phải xử lý thông tin của họ với quá nhiều công việc và có quá nhiều tham số. Bạn cảm thấy điều này, nếu bạn đưa ra cho nhiều phương thức của mình một tham số bằng nhau nhất định và tất cả các phương thức đều thực hiện một cách rất giống với tham số này. Trong tình huống đó, mã của bạn sẽ bắt đầu phình to. Cuối cùng, bạn sẽ cuộn nhiều màn hình lên xuống để có được những thứ đơn giản cùng nhau. Ở đây, một cấu trúc lại có thể giúp: giới thiệu một biến đối tượng và một lối vào rõ ràng cho nó. Sau đó, miễn phí tất cả các phương pháp.

  4. Cuối cùng nhưng không kém phần quan trọng: Nếu nhiều biến thể hiện của một lớp có setter và getter của chúng, thì nó có thể chỉ ra rằng các lớp khác không sử dụng lớp đầu tiên này đúng cách. Có một cuộc thảo luận về " Tại sao getters và setters là xấu xa ". Tóm lại, ý tưởng là, nếu một lớp Rectanglecung cấp một số getX()và hàng chục lớp khác sử dụng rectangle.getX(), thì bạn đang viết mã không mạnh mẽ chống lại "hiệu ứng gợn" (khoảng cách thay đổi mã ảnh hưởng đến mã khác bao xa). Đơn giản chỉ cần hỏi những gì xảy ra nếu bạn thay đổi loại từ intsang . Vì vậy, rất gián tiếp, mã trùng lặp có thể xuất hiện từ nhiều biến thể hiện, vì nhiều lớp xung quanh sử dụng nhiều getters và setters làm những việc rất giống nhau, tức là những thứ được sao chép, tốt hơn nên được di chuyển bên trong lớp. double ? Theo cuộc thảo luận này, rectangle.getX()trên thực tế , nhiều cuộc gọi nên được gọi làrectanlge.calculateThisThingForMe()

Nhiều hoặc một vài biến thể hiện vẫn là một sự đánh đổi vĩnh viễn, thay đổi cả hai cách trong khi phần mềm đang phát triển.


Trích dẫn R-to-P quá chung chung, đó là lý do tại sao tôi thích câu trả lời này. Điều đáng nói của tôi là: nếu chúng ta phơi bày đủ các thuộc tính mà khách hàng có thể, và sẽ, lấy chúng và viết phiên bản riêng của một chức năng nhất định - # 4 ở trên. Vấn đề có thể đi sâu như thành phần đối tượng - xem # 2: Tôi thấy điều này quá thường xuyên trong mã của chúng tôi. (a) "tại sao họ không sử dụng lớp <anything> (để ăn mòn một số trạng thái không có tổ chức này)?" hoặc (b) "Tại sao họ không tạo ra một lớp mới? Tôi không thể theo dõi tất cả." Và chắc chắn rằng chúng ta có một số lớp sao chép bên trong chức năng vì thiếu một lớp kết hợp.
radarbob

6

Nói một cách đơn giản: sự phân tách kém các mối quan tâm trong mã, dẫn đến mã không theo mô-đun, dẫn đến việc sử dụng lại kém, dẫn đến mã trùng lặp.

Nếu bạn không bao giờ thử lặp lại chức năng, bạn sẽ không nhận được mã trùng lặp và nhiều biến thể hiện, sẽ không thành vấn đề.

Nếu bạn cố gắng lặp lại chức năng, thì mã nguyên khối, không phải là mô-đun, không thể được sử dụng lại. Nó làm quá nhiều và chỉ có thể làm những gì nó làm. Để làm một cái gì đó tương tự, nhưng không giống nhau, việc cắt và dán "dễ dàng" hơn là phá vỡ mã nguyên khối. Các lập trình viên kinh nghiệm biết rằng mã trùng lặp là con đường dẫn đến địa ngục.

Vì vậy, trong khi nhiều biến thể tự nó không phải là nguyên nhân gốc rễ của vấn đề thì đó là một "mùi" mạnh mà vấn đề đang đến.

Ngôn ngữ "không thể lùi xa" yếu hơn nói "chắc chắn phải tuân theo" vì vậy tác giả không cho rằng nó phải xảy ra nhưng cuối cùng sẽ xảy ra; nếu bạn cần sử dụng lại chức năng nhưng không thể vì mã không phải là mô-đun.

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.