Nguyên thủy, chẳng hạn như string
hoặc int
, không có ý nghĩa trong một lĩnh vực kinh doanh. Hậu quả trực tiếp của việc này là bạn có thể sử dụng nhầm URL khi ID sản phẩm được mong đợi hoặc sử dụng số lượng khi mong đợi giá .
Đây cũng là lý do tại sao thử thách Object Calisthenics có tính năng bao bọc nguyên thủy như một trong những quy tắc của nó:
Quy tắc 3: Bọc tất cả các nguyên thủy và Chuỗi
Trong ngôn ngữ Java, int là một nguyên thủy, không phải là một đối tượng thực sự, vì vậy nó tuân theo các quy tắc khác với các đối tượng. Nó được sử dụng với một cú pháp không hướng đối tượng. Quan trọng hơn, một int riêng của nó chỉ là một vô hướng, vì vậy nó không có ý nghĩa. Khi một phương thức lấy một int làm tham số, tên phương thức cần thực hiện tất cả các công việc thể hiện ý định. Nếu cùng một phương thức lấy một giờ làm tham số, thì việc xem những gì đang diễn ra sẽ dễ dàng hơn nhiều.
Tài liệu tương tự giải thích rằng có một lợi ích bổ sung:
Các đối tượng nhỏ như Giờ hoặc Tiền cũng cho chúng ta một vị trí rõ ràng để đặt hành vi mà nếu không sẽ bị vứt bừa bãi xung quanh các lớp khác .
Thật vậy, khi các nguyên thủy được sử dụng, thường rất khó để theo dõi vị trí chính xác của mã liên quan đến các loại đó, thường dẫn đến sao chép mã nghiêm trọng . Nếu có Price: Money
lớp, việc tìm phạm vi kiểm tra bên trong là điều tự nhiên. Nếu, thay vào đó, một int
(tệ hơn, a double
) được sử dụng để lưu trữ giá sản phẩm, ai nên xác nhận phạm vi? Sản phẩm? Việc giảm giá? Các xe đẩy?
Cuối cùng, một lợi ích thứ ba không được đề cập trong tài liệu là khả năng thay đổi tương đối dễ dàng loại cơ bản. Nếu hôm nay tôi ProductId
có short
loại cơ bản và sau này tôi cần sử dụng int
thay vào đó, rất có thể mã để thay đổi sẽ không bao trùm toàn bộ cơ sở mã.
Hạn chế và một lập luận tương tự áp dụng cho mọi quy tắc của bài tập Object Calisthenics là nếu nhanh chóng trở nên quá sức để tạo ra một lớp cho mọi thứ . Nếu Product
chứa ProductPrice
những thứ thừa kế từ PositivePrice
đó thừa kế từ Price
đó thừa hưởng từ đó Money
, thì đây không phải là kiến trúc sạch, mà là một mớ hỗn độn hoàn toàn để tìm một thứ duy nhất, một người bảo trì nên mở vài chục tệp mỗi lần.
Một điểm khác cần xem xét là chi phí (về dòng mã) của việc tạo các lớp bổ sung. Nếu các trình bao bọc là bất biến (thường là như vậy), điều đó có nghĩa là, nếu chúng tôi lấy C #, bạn phải có, trong ít nhất là trong trình bao bọc:
- Người nhận tài sản,
- Lĩnh vực hỗ trợ của nó,
- Một hàm tạo gán giá trị cho trường sao lưu,
- Một phong tục
ToString()
,
- Nhận xét tài liệu XML (tạo ra rất nhiều dòng),
- A
Equals
và GetHashCode
ghi đè (cũng rất nhiều LỘC).
và cuối cùng, khi có liên quan:
- Một DebuggerDisplay thuộc tính,
- Ghi đè
==
và !=
toán tử,
- Cuối cùng, quá tải toán tử chuyển đổi ngầm định để chuyển đổi liền mạch đến và từ loại được đóng gói,
- Hợp đồng mã (bao gồm cả bất biến, là một phương thức khá dài, với ba thuộc tính của nó),
- Một số bộ chuyển đổi sẽ được sử dụng trong quá trình tuần tự hóa XML, tuần tự hóa JSON hoặc lưu trữ / tải một giá trị đến / từ cơ sở dữ liệu.
Một trăm LỘC cho một trình bao bọc đơn giản làm cho nó khá cấm, đó cũng là lý do tại sao bạn có thể hoàn toàn chắc chắn về lợi nhuận lâu dài của trình bao bọc đó. Khái niệm phạm vi được giải thích bởi Thomas Junk đặc biệt có liên quan ở đây. Viết một trăm LỘC để thể hiện một ProductId
sử dụng trên toàn bộ cơ sở mã của bạn trông khá hữu ích. Viết một lớp có kích thước này cho một đoạn mã làm cho ba dòng trong một phương thức trở nên nghi ngờ hơn nhiều.
Phần kết luận:
Không bao gồm các nguyên hàm trong các lớp có ý nghĩa trong lĩnh vực kinh doanh của ứng dụng khi (1) nó giúp giảm lỗi, (2) giảm nguy cơ sao chép mã hoặc (3) giúp thay đổi loại cơ bản sau này.
Đừng bao bọc tự động mọi nguyên thủy bạn tìm thấy trong mã của mình: có nhiều trường hợp sử dụng string
hoặc int
hoàn toàn tốt.
Trong thực tế, trong public string CreateNewThing()
, trả về một thể hiện của ThingId
lớp thay vì string
có thể giúp đỡ, nhưng bạn cũng có thể:
Trả về một thể hiện của Id<string>
lớp, đó là một đối tượng của kiểu chung cho biết kiểu bên dưới là một chuỗi. Bạn có lợi ích về khả năng đọc, không có nhược điểm là phải duy trì nhiều loại.
Trả về một thể hiện của Thing
lớp. Nếu người dùng chỉ cần ID, điều này có thể dễ dàng thực hiện với:
var thing = this.CreateNewThing();
var id = thing.Id;