Tên cho antipotype này? Các trường dưới dạng biến cục bộ [đã đóng]


68

Trong một số mã tôi đang xem xét, tôi thấy những thứ tương đương với đạo đức như sau:

public class Foo
{
    private Bar bar;

    public MethodA()
    {
        bar = new Bar();
        bar.A();
        bar = null;
    }

    public MethodB()
    {
        bar = new Bar();
        bar.B();
        bar = null;
    }
}

Các lĩnh vực barđây là một cách logic một biến địa phương, như giá trị của nó không bao giờ có ý định để duy trì qua các cuộc gọi phương pháp. Tuy nhiên, vì nhiều phương thức Foocần một đối tượng kiểu Bar, tác giả mã gốc vừa tạo một trường kiểu Bar.

  1. Điều này rõ ràng là xấu, phải không?
  2. Có một tên cho antipotype này?

60
Vâng, đó là một cái mới. Hy vọng lớp này không được sử dụng trong bối cảnh đa luồng hoặc bạn sẽ có những khoảng thời gian thú vị phía trước!
TMN

8
Điều này thực sự không phổ biến? Tôi đã nhìn thấy điều này nhiều lần trong sự nghiệp của tôi.
JSB

32
@TMN Nó không phải là chủ đề an toàn, nhưng điều tồi tệ hơn, nó thậm chí không được phát hành lại. Nếu bất kỳ mã nào trong MethodAhoặc MethodBgây ra MethodAhoặc MethodBđược gọi theo bất kỳ cách nào (và barđược sử dụng lại, trong trường hợp bar.{A,B}()là người phạm tội), bạn có vấn đề tương tự ngay cả khi không có bất kỳ sự tương tranh nào.

73
Chúng ta có phải có một tên cho mọi điều ngu ngốc ai đó có thể làm? Chỉ cần gọi nó là một ý tưởng tồi.
Caleb

74
Khó mà không gọi nó là tư nhân chống lủng lẳng.
psr

Câu trả lời:


86

Điều này rõ ràng là xấu, phải không?

Vâng

  • Nó làm cho các phương thức không được reentrant, đó là một vấn đề nếu chúng được gọi trên cùng một đệ quy hoặc trong một bối cảnh đa luồng.

  • Nó có nghĩa là trạng thái từ một cuộc gọi bị rò rỉ sang một cuộc gọi khác (nếu bạn quên tái cấp phép lại).

  • Nó làm cho mã khó hiểu vì bạn phải kiểm tra ở trên để chắc chắn mã đang thực sự làm gì. (Tương phản với việc sử dụng các biến cục bộ.)

  • Nó làm cho mỗi Footrường hợp lớn hơn nó cần phải được. (Và hãy tưởng tượng làm điều này cho N biến ...)

Có một tên cho antipotype này?

IMO, điều này không xứng đáng được gọi là một antipotype. Nó chỉ là một thói quen mã hóa xấu / lạm dụng các cấu trúc Java / mã crap. Đó là thứ mà bạn có thể thấy trong mã của một sinh viên khi sinh viên đã bỏ qua các bài giảng và / hoặc không có khả năng lập trình. Nếu bạn thấy nó trong mã sản xuất, đó là một dấu hiệu cho thấy bạn cần thực hiện nhiều đánh giá mã hơn ...


Đối với bản ghi, cách chính xác để viết này là:

public class Foo
{
    public methodA()
    {
        Bar bar = new Bar();  // Use a >>local<< variable!!
        bar.a();
    }

    // Or more concisely (in this case) ...
    public methodB()
    {
        new Bar().b();
    }
}

Lưu ý rằng tôi cũng đã sửa các tên phương thức và biến để tuân thủ các quy tắc kiểu được chấp nhận cho các mã định danh Java.


11
Tôi sẽ nói "Nếu bạn thấy nó trong mã sản xuất, đó là một dấu hiệu cho thấy bạn nên xem xét lại quy trình tuyển dụng của mình "
Beta

@Beta - điều đó cũng vậy, mặc dù bạn sẽ có thể sửa các thói quen mã hóa xấu như thế với việc xem xét mã mạnh mẽ.
Stephen C

+1 cho bit về nhiều đánh giá mã hơn. Bất chấp những gì mọi người nghĩ, cải thiện thực hành tuyển dụng sẽ không ngăn được loại vấn đề này - tuyển dụng là một trò nhảm nhí, điều tốt nhất bạn có thể làm là tải xúc xắc có lợi cho bạn.
mattnz

@StephenC "Nó làm cho các phương thức không được reentrant, đó là một vấn đề nếu chúng được gọi trên cùng một ví dụ đệ quy hoặc trong một bối cảnh đa luồng." . Tôi biết reentrancy là gì nhưng không thể thấy một điểm cho điều này ở đây vì các phương thức không sử dụng bất kỳ khóa nào? Bạn có thể giải thích được không .
Geek

@Geek - Bạn đang tập trung quá nhiều vào ví dụ cụ thể. Tôi đang nói về trường hợp chung trong đó phương thức có thể được gọi từ nhiều luồng hoặc đệ quy.
Stephen C

39

Tôi sẽ gọi nó là phạm vi lớn không cần thiết cho một biến. Cài đặt này cũng cho phép điều kiện cuộc đua nếu nhiều luồng truy cập Phương thứcA và Phương thứcB.


12
Cụ thể, tôi nghĩ "phạm vi biến" là tên của vấn đề ở đây. Người này cần tìm hiểu các biến cục bộ là gì và cách thức / thời điểm sử dụng chúng. Mẫu tích cực hoặc quy tắc chung là sử dụng phạm vi nhỏ nhất có sẵn cho bạn cho mỗi biến và chỉ mở rộng nó khi cần. Để rõ ràng, lỗi này không chỉ là phong cách xấu. Mã hóa một điều kiện cuộc đua như thế này là một lỗi.
GlenPeterson

30

Đây là một trường hợp cụ thể của một mô hình chung được gọi là global doorknobbing. Khi xây dựng một ngôi nhà, thật hấp dẫn khi chỉ mua một tay nắm cửa và để nó nằm xung quanh. Khi ai đó muốn sử dụng cửa hoặc tủ, họ chỉ cần nắm lấy một tay nắm cửa toàn cầu đó. Nếu tay nắm cửa đắt tiền, nó có thể là một thiết kế tốt.

Thật không may, khi bạn của bạn ghé qua và tay nắm cửa được sử dụng đồng thời ở hai nơi khác nhau, thực tế tan vỡ. Nếu tay nắm cửa đắt đến mức bạn chỉ có thể mua một cái, thì thật đáng để xây dựng một hệ thống cho phép mọi người chờ đến lượt cho tay nắm cửa.

Trong trường hợp này, tay nắm cửa chỉ là một tài liệu tham khảo, vì vậy nó rẻ. Nếu tay nắm cửa là một đối tượng thực tế (và họ đang sử dụng lại đối tượng thay vì chỉ tham chiếu), thì nó có thể đủ đắt để trở thành một prudent global doorknob. Tuy nhiên, khi nó rẻ, nó được gọi là a cheapskate global doorknob.

Ví dụ của bạn là của sự cheapskateđa dạng.


19

Mối quan tâm chính ở đây sẽ là sự tương tranh - Nếu Foo đang được sử dụng bởi nhiều luồng, bạn có vấn đề.

Ngoài ra, điều đó thật ngớ ngẩn - các biến cục bộ quản lý vòng đời của chính họ một cách hoàn hảo. Thay thế chúng bằng các biến thể hiện cần được vô hiệu hóa khi chúng không còn hữu ích là lời mời lỗi.


15

Đó là một trường hợp cụ thể của "phạm vi không phù hợp", với một bên là "tái sử dụng biến".


7

Nó không phải là một mô hình chống. Chống mẫu có một số tài sản làm cho nó có vẻ như là một ý tưởng tốt, dẫn đến mọi người thực hiện nó có chủ đích; họ đã lên kế hoạch theo mô hình và sau đó nó đi sai lầm khủng khiếp.

Đó cũng là điều tạo nên những cuộc tranh luận về việc liệu một thứ gì đó là một mẫu, một mẫu chống hoặc một mẫu thường được áp dụng sai mà vẫn được sử dụng ở một số nơi.

Điều này chỉ sai.

Để thêm một chút nữa.

Mã này là mê tín, hoặc tốt nhất là một thực hành sùng bái hàng hóa.

Một sự mê tín là một cái gì đó được thực hiện mà không có sự biện minh rõ ràng. Nó có thể liên quan đến một cái gì đó thực sự, nhưng kết nối không logic.

Một thực hành sùng bái hàng hóa là một trong đó bạn cố gắng sao chép một thứ gì đó mà bạn đã học được từ một nguồn hiểu biết hơn, nhưng bạn thực sự sao chép các vật phẩm bề mặt chứ không phải là quá trình (được đặt tên cho một giáo phái ở Papua New Guinea, người sẽ thực hiện máy bay điều khiển máy bay ra khỏi tre với hy vọng làm cho máy bay WWII của Nhật Bản và Mỹ quay trở lại).

Trong cả hai trường hợp này, không có trường hợp thực tế nào được thực hiện.

Một mô hình chống là một nỗ lực nhằm cải thiện hợp lý, dù là nhỏ (phân nhánh thêm đó để giải quyết trường hợp bổ sung đó phải xử lý, dẫn đến mã spaghetti) hoặc trong trường hợp lớn mà bạn rất cố tình thực hiện một mẫu rằng hoặc là mất uy tín hoặc tranh luận (nhiều người sẽ mô tả các singletons như vậy, với một số loại trừ một đối tượng chỉ ghi - ví dụ: ghi nhật ký hoặc chỉ đọc các đối tượng cài đặt cấu hình - và một số sẽ kết án ngay cả những đối tượng đó) hoặc người khác đang giải quyết vấn đề sai (khi .NET lần đầu tiên được đưa ra, MS đã đề xuất một mô hình xử lý xử lý khi bạn có cả trường không được quản lý và trường được quản lý dùng một lần - nó thực sự xử lý tình huống đó rất tốt, nhưng vấn đề thực sự là bạn đã mắc phải cả hai loại trường trong cùng một lớp).

Như vậy, một mô hình chống đối là một thứ mà một người thông minh biết ngôn ngữ, miền có vấn đề và các thư viện có sẵn sẽ cố tình làm, điều đó vẫn có (hoặc được cho là có) nhược điểm lấn át nhược điểm.

Vì không ai trong chúng ta bắt đầu biết một ngôn ngữ nhất định, miền có vấn đề và các thư viện có sẵn, và vì mọi người đều có thể bỏ lỡ điều gì đó khi họ đi từ giải pháp hợp lý này sang giải pháp khác (ví dụ: bắt đầu lưu trữ một thứ gì đó trong một lĩnh vực để sử dụng tốt, sau đó thử tái cấu trúc nó đi nhưng không hoàn thành công việc, và bạn sẽ kết thúc với mã như trong câu hỏi), và vì đôi khi chúng ta bỏ lỡ mọi thứ trong học tập, chúng ta đã tạo ra một số mã mê tín dị đoan hoặc hàng hóa tại một số điểm . Điều tốt, là chúng thực sự rõ ràng hơn để xác định và sửa chữa hơn so với các mô hình chống. Các mô hình chống thực sự được cho là không chống lại các mô hình, hoặc có một số chất lượng hấp dẫn, hoặc ít nhất có một số cách dụ dỗ một trong số chúng ngay cả khi được xác định là xấu (quá nhiều và quá ít lớp đều không gây tranh cãi, nhưng tránh được một dẫn đến cái khác).


1
Nhưng mọi người đừng nghĩ rằng đây là một ý tưởng tốt, có lẽ bởi vì họ nghĩ rằng đó là một hình thức tái sử dụng mã.
JSB

Người mới bắt đầu dường như thường nghĩ rằng việc khai báo hai biến bằng cách nào đó đòi hỏi gấp đôi không gian và do đó thích sử dụng lại các biến. Điều này cho thấy sự hiểu lầm về mô hình bộ nhớ (lưu trữ miễn phí so với ngăn xếp, khả năng sử dụng lại các vị trí ngăn xếp) và tối ưu hóa mà tất cả các trình biên dịch có thể thực hiện. Do đó, tôi cho rằng một người mới bắt đầu có thể coi việc tái sử dụng biến là một ý tưởng tốt, vì vậy nó có thể được phân loại là một phản mẫu.
Philipp

Điều đó làm cho nó trở thành một mê tín, không phải là một phản hạt.
Jon Hanna

3

(1) Tôi sẽ nói nó không tốt.

Đó là việc thực hiện nhà thủ công giữ cho ngăn xếp có thể tự động thực hiện với các biến cục bộ.

Không có lợi ích hiệu năng vì "mới" được gọi là mỗi lần gọi phương thức.

EDIT: Dấu chân bộ nhớ của lớp lớn hơn vì con trỏ thanh luôn chiếm bộ nhớ trong suốt vòng đời của lớp. Nếu con trỏ thanh là cục bộ, thì nó sẽ chỉ sử dụng bộ nhớ trong suốt vòng đời của phương thức gọi. Bộ nhớ cho con trỏ chỉ là một giọt nước trong đại dương, nhưng nó vẫn là một giọt không cần thiết.

Thanh được hiển thị cho các phương thức khác trong lớp. Các phương pháp không sử dụng thanh không nên nhìn thấy nó.

Lỗi dựa trên nhà nước. Trong trường hợp cụ thể này, lỗi cơ sở trạng thái chỉ xảy ra trong đa luồng vì "mới" được gọi mỗi lần.

(2) Tôi không biết có tên cho nó không vì nó thực sự là một số vấn đề, không phải là một vấn đề.
- Dịch vụ dọn phòng thông thường khi có sẵn tự động -
Trạng thái cần thiết - trạng thái
tồn tại lâu hơn trong suốt cuộc đời -
Khả năng hiển thị hoặc phạm vi quá cao


2

Tôi sẽ gọi nó là "Xenophobe lang thang". Nó muốn bị bỏ lại một mình nhưng cuối cùng không biết nó ở đâu và nó là gì. Vì vậy, đó là một điều xấu như những người khác đã tuyên bố.


2

Đi ngược lại hạt gạo ở đây nhưng trong khi tôi không coi ví dụ đã cho là phong cách mã hóa tốt như ở dạng hiện tại của nó, thì mẫu đó tồn tại trong khi thực hiện thử nghiệm đơn vị.

Cách làm đơn vị này khá chuẩn

public class BarTester
{
    private Bar bar;

    public Setup() { bar = new Bar(); }
    public Teardown() { bar = null; }

    public TestMethodA()
    {
        bar.A();        
    }

    public TestMethodB()
    {
        bar.B();
    }
}

chỉ là một cấu trúc lại mã tương đương của mã OP này

public class BarTester
{
    private Bar bar;

    public TestMethodA()
    {
        bar = new Bar();
        bar.A();
        bar = null;
    }

    public TestMethodB()
    {
        bar = new Bar();
        bar.B();
        bar = null;
    }
}

Tôi sẽ không bao giờ viết mã như được đưa ra bằng ví dụ OP, nó hét lên tái cấu trúc, nhưng tôi xem xét các mô hình là không hợp lệ hay một antipattern .


Trong trường hợp đó, vật cố được khởi tạo độc lập cho từng thử nghiệm và các vấn đề liên quan đến tái sử dụng biến đổi hoặc đồng thời không xảy ra. Trong trường hợp chung (kiểm tra đơn vị bên ngoài) không biết có nhiều nhất một phương thức được gọi trên mỗi đối tượng hay không.
Philipp

1
@Philipp - Tôi không tranh chấp vấn đề tái sử dụng hoặc đồng thời nhưng câu hỏi của OP là về mẫu mà chúng thường được sử dụng trong kiểm tra đơn vị. Thực tế là vật cố được khởi tạo cho mỗi thử nghiệm là một chi tiết triển khai của khung thử nghiệm. Ngay cả trong thử nghiệm đơn vị, mẫu chỉ an toàn khi khung thử nghiệm được sử dụng vì nó được sử dụng. Lý do tương tự áp dụng khi sử dụng mẫu này trong mã sản xuất.
Lieven Keersmaekers

Không cần thiết barđể null, JUnit nào tạo ra một trường hợp thử nghiệm mới cho mỗi phương pháp thử nghiệm.
oberlies

2

Mùi mã này được gọi là Trường tạm thời trong Tái cấu trúc bởi Beck / Fowler.

http://sourcemaking.com/refactoring/t tạm-field

Được chỉnh sửa để thêm giải thích theo yêu cầu của người kiểm duyệt: Bạn có thể đọc thêm về mùi mã trong URL được tham chiếu ở trên hoặc trong bản sao cứng của cuốn sách. Vì OP đang tìm kiếm tên cho mùi antipotype / code đặc biệt này, tôi nghĩ rằng việc trích dẫn một tài liệu tham khảo không được đề cập đến từ một nguồn đã được xác lập trên 10 tuổi sẽ rất hữu ích, mặc dù tôi hoàn toàn nhận ra rằng tôi đến muộn trò chơi về câu hỏi này, vì vậy không chắc câu trả lời sẽ được bình chọn hoặc chấp nhận.

Nếu nó không quá quảng cáo cá nhân, tôi cũng tham khảo và giải thích mùi mã đặc biệt này trong khóa học Pluralsight sắp tới của tôi, Tái cấu trúc các nguyên tắc cơ bản, mà tôi mong đợi sẽ được xuất bản vào tháng 8 năm 2013.

Bằng cách thêm nhiều giá trị hơn, hãy nói về cách khắc phục vấn đề cụ thể này. Có một số lựa chọn. Nếu trường thực sự chỉ được sử dụng bởi một phương thức, thì nó có thể được hạ cấp thành một biến cục bộ. Tuy nhiên, nếu nhiều phương thức đang sử dụng trường để giao tiếp (thay cho tham số), thì đây là trường hợp cổ điển được mô tả trong Tái cấu trúc và có thể được sửa bằng cách thay thế trường bằng tham số hoặc nếu các phương thức hoạt động với mã này được theo sát có liên quan, Lớp trích xuất có thể được sử dụng để kéo các phương thức và (các) trường vào lớp riêng của chúng, trong đó trường luôn ở trạng thái hợp lệ (có thể được đặt trong khi xây dựng) và thể hiện trạng thái của lớp mới này. Nếu đi theo tuyến tham số, nhưng có quá nhiều giá trị để vượt qua, một tùy chọn khác là giới thiệu Đối tượng tham số mới,


Điều quan trọng cần lưu ý là Trường tạm thời thường được yêu cầu cho tái cấu trúc Lớp trích xuất. Nhưng ai đó biết điều này có lẽ sẽ không kiểm tra mã ở trạng thái trung gian này.
oberlies

1

Tôi muốn nói khi bạn đi thẳng vào nó, đây thực sự là một sự thiếu gắn kết và tôi có thể đặt cho nó cái tên "Sự gắn kết sai lầm". Tôi đã xu (hoặc nếu tôi nhận được nó từ một nơi nào đó và quên nó, "mượn") thuật ngữ này bởi vì lớp dường như gắn kết trong đó các phương thức của nó dường như hoạt động trên một trường thành viên. Tuy nhiên, trong thực tế họ không, có nghĩa là sự gắn kết rõ ràng là thực sự sai.

Về việc nó có tệ hay không, tôi nói rõ ràng là như vậy, và tôi nghĩ Stephen C làm một công việc tuyệt vời để giải thích lý do tại sao. Tuy nhiên, cho dù nó có xứng đáng được gọi là "chống mẫu" hay không, tôi nghĩ nó và bất kỳ mô hình mã hóa nào khác có thể làm với một nhãn, vì điều đó thường giúp giao tiếp dễ dàng hơn.


1

Ngoài các vấn đề đã được đề cập, sử dụng phương pháp này trong môi trường không có bộ sưu tập rác tự động (ví dụ C ++) sẽ dẫn đến rò rỉ bộ nhớ, vì các đối tượng tạm thời không được giải phóng sau khi sử dụng. (Mặc dù điều này có vẻ hơi xa vời, nhưng có những người ở ngoài đó sẽ thay đổi 'null' thành 'NULL' và rất vui khi mã được biên dịch.)


1

Điều này đối với tôi giống như một sự áp dụng sai lầm khủng khiếp của mô hình Flykg. Thật không may, tôi đã biết một vài nhà phát triển phải sử dụng cùng một "thứ" trong các phương thức khác nhau và chỉ cần kéo nó ra một trường riêng trong một nỗ lực sai lầm trong việc tiết kiệm bộ nhớ hoặc cải thiện hiệu suất hoặc một số tối ưu hóa giả khác. Trong tâm trí của họ, họ đang cố gắng giải quyết một vấn đề tương tự vì Flykg chỉ nhằm giải quyết vấn đề họ đang làm trong tình huống thực sự không phải là vấn đề cần giải quyết.


-1

Tôi đã gặp điều này nhiều lần, thông thường khi làm mới mã được viết trước đây bởi một người đã chọn VBA For Dummies làm tiêu đề đầu tiên của họ và tiếp tục viết một hệ thống tương đối lớn bằng bất kỳ ngôn ngữ nào họ đã vấp phải.

Nói rằng thực tế lập trình thực sự tồi là đúng, nhưng nó có thể là kết quả của việc không có tài nguyên được đánh giá qua internet và ngang hàng như tất cả chúng ta đều thích ngày nay có thể đã hướng dẫn nhà phát triển ban đầu đi theo con đường "an toàn hơn".

Mặc dù vậy, nó không thực sự xứng đáng với thẻ "antipotype" - nhưng thật tuyệt khi thấy những gợi ý về cách OP có thể được mã hóa lại.


1
Chào mừng bạn đến với lập trình viên Stack Exchange, cảm ơn vì đã nhập câu trả lời đầu tiên của bạn. Có vẻ như bạn đã bỏ phiếu giảm giá, có thể vì một lý do được liệt kê trong các chương trình FAQ.stackexchange.com/faq . Câu hỏi thường gặp đưa ra gợi ý tuyệt vời về việc đưa ra câu trả lời hiệu quả (và được bình chọn). Đôi khi mọi người đủ tử tế để thêm một ghi chú về việc bỏ phiếu xuống để cho biết nếu nó sai theo một cách nào đó, trùng lặp, ý kiến ​​mà không có bằng chứng, hoặc một tôi cũng lặp lại một câu trả lời trước đó. Hầu hết chúng ta đã bỏ phiếu, đóng hoặc xóa câu trả lời, vì vậy đừng quan tâm. Nó chỉ là một phần của việc bắt đầu. Chào mừng bạn
DeveloperDon
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.