Có phải tránh được vấn đề yo-yo là một lý do hợp lệ để cho phép nỗi ám ảnh nguyên thủy của người Hồi giáo không?


42

Theo Khi nào nỗi ám ảnh nguyên thủy không phải là mùi mã? , Tôi nên tạo một đối tượng ZipCode để thể hiện mã zip thay vì đối tượng String.

Tuy nhiên, theo kinh nghiệm của tôi, tôi thích nhìn thấy

public class Address{
    public String zipCode;
}

thay vì

public class Address{
    public ZipCode zipCode;
}

bởi vì tôi nghĩ cái thứ hai yêu cầu tôi chuyển sang lớp ZipCode để hiểu chương trình.

Và tôi tin rằng tôi cần phải di chuyển giữa nhiều lớp để xem định nghĩa nếu mọi trường dữ liệu nguyên thủy được thay thế bởi một lớp, cảm giác như thể đang gặp phải vấn đề yo-yo (một kiểu chống).

Vì vậy, tôi muốn chuyển các phương thức ZipCode sang một lớp mới, ví dụ:

Cũ:

public class ZipCode{
    public boolean validate(String zipCode){
    }
}

Mới:

public class ZipCodeHelper{
    public static boolean validate(String zipCode){
    }
}

để chỉ người nào cần xác thực mã zip mới phụ thuộc vào lớp ZipCodeHelper. Và tôi đã tìm thấy một "lợi ích" khác của việc giữ nỗi ám ảnh nguyên thủy: nó giữ cho lớp trông giống như dạng tuần tự của nó, nếu có, ví dụ: một bảng địa chỉ có mã zip cột cột.

Câu hỏi của tôi là, "tránh vấn đề yo-yo" (di chuyển giữa các định nghĩa lớp) là một lý do hợp lệ để cho phép "nỗi ám ảnh nguyên thủy"?


9
@ jpmc26 Sau đó, bạn sẽ bị sốc khi thấy đối tượng mã zip của chúng tôi phức tạp đến mức nào - không nói nó đúng, nhưng nó tồn tại
Jared Goguen

9
@ jpmc26, tôi không thấy cách bạn chuyển từ "phức tạp" sang "được thiết kế tồi". Mã phức tạp thường là kết quả của mã đơn giản tiếp xúc với sự phức tạp của thế giới thực chứ không phải là thế giới lý tưởng mà chúng ta mong muốn tồn tại. "Quay lại chức năng hai trang đó. Vâng, tôi biết, đó chỉ là một chức năng đơn giản để hiển thị một cửa sổ, nhưng nó mọc rất ít lông và những thứ trên đó và không ai biết tại sao. Chà, tôi sẽ nói cho bạn biết tại sao: đó là lỗi sửa lỗi."
Kyralessa

19
@ jpmc26 - điểm của các đối tượng gói như ZipCode là loại an toàn. Mã zip không phải là một chuỗi, nó là một mã zip. Nếu một hàm mong đợi mã zip, bạn chỉ có thể truyền mã zip chứ không phải chuỗi.
Thưởng thức Ždralo

4
Điều này cảm thấy ngôn ngữ cụ thể cao, các ngôn ngữ khác nhau làm những điều khác nhau ở đây. @ DavorŽdralo Trong cùng một khoảng, chúng ta cũng nên thêm rất nhiều kiểu số. "Chỉ các số nguyên dương", "chỉ các số chẵn" cũng có thể là các loại.
paul23

6
@ paul23 Đúng vậy, và lý do chính chúng ta không có đó là rất nhiều ngôn ngữ không hỗ trợ các cách thức thanh lịch để định nghĩa chúng. Hoàn toàn hợp lý khi định nghĩa "tuổi" là một loại khác với "nhiệt độ tính bằng độ", nếu chỉ để "userAge == currentTem Nhiệt độ" được phát hiện là vô nghĩa.
IMSoP

Câu trả lời:


116

Giả định là bạn không cần phải yo-yo đến lớp ZipCode để hiểu lớp Địa chỉ. Nếu ZipCode được thiết kế tốt, thì rõ ràng những gì nó làm chỉ bằng cách đọc lớp Địa chỉ.

Các chương trình không được đọc từ đầu đến cuối - thông thường các chương trình quá phức tạp để thực hiện điều này. Bạn không thể giữ tất cả các mã trong một chương trình trong tâm trí của bạn cùng một lúc. Vì vậy, chúng tôi sử dụng trừu tượng và đóng gói để "chia nhỏ" chương trình thành các đơn vị có ý nghĩa, do đó bạn có thể xem một phần của chương trình (nói lớp Địa chỉ) mà không cần phải đọc tất cả mã mà nó phụ thuộc.

Ví dụ: tôi chắc chắn rằng bạn không đọc mã nguồn cho Chuỗi mỗi khi bạn gặp Chuỗi trong mã.

Đổi tên lớp từ ZipCode thành ZipCodeHelper cho thấy hiện tại có hai khái niệm riêng biệt: mã zip và trình trợ giúp mã zip. Vì vậy, phức tạp gấp đôi. Và bây giờ hệ thống loại không thể giúp bạn phân biệt giữa một chuỗi tùy ý và mã zip hợp lệ vì chúng có cùng loại. Đây là nơi "ám ảnh" là phù hợp: Bạn đang đề xuất một giải pháp thay thế phức tạp hơn và kém an toàn hơn chỉ vì bạn muốn tránh một kiểu bao bọc đơn giản xung quanh nguyên thủy.

Sử dụng một nguyên thủy là IMHO hợp lý trong trường hợp không có xác nhận hoặc logic khác tùy thuộc vào loại cụ thể này. Nhưng ngay khi bạn thêm bất kỳ logic nào, sẽ đơn giản hơn nhiều nếu logic này được gói gọn với loại.

Đối với việc tuần tự hóa tôi nghĩ rằng nó có vẻ như là một hạn chế trong khung bạn đang sử dụng. Chắc chắn bạn sẽ có thể tuần tự hóa ZipCode thành một chuỗi hoặc ánh xạ nó tới một cột trong cơ sở dữ liệu.


2
Tôi đồng ý với phần "đơn vị có ý nghĩa" (chính-), nhưng không nhiều đến mức xác thực mã zip và mã zip là cùng một khái niệm. ZipCodeHelper(mà tôi muốn gọi ZipCodeValidator) rất có thể thiết lập kết nối với dịch vụ web để thực hiện công việc đó. Đó không phải là một phần của trách nhiệm duy nhất "giữ dữ liệu mã zip". Việc làm cho hệ thống loại không cho phép mã zip không hợp lệ vẫn có thể đạt được bằng cách làm cho hàm ZipCodetạo tương đương với gói riêng tư của Java và gọi đó là mã ZipCodeFactoryluôn gọi trình xác nhận hợp lệ.
R. Schmitz

16
@ R.Schmitz: Đó không phải là "trách nhiệm" nghĩa là gì theo nguyên tắc trách nhiệm duy nhất. Nhưng trong mọi trường hợp, tất nhiên bạn nên sử dụng bao nhiêu lớp mà bạn cần miễn là bạn đóng gói mã zip và xác nhận hợp lệ của nó. OP đề nghị một người trợ giúp thay vì đóng gói mã zip, đó là một ý tưởng tồi.
JacquesB

1
Tôi muốn tôn trọng không đồng ý. SRP có nghĩa là một lớp nên có "một, và chỉ một, lý do cần thay đổi" (thay đổi trong "mã zip bao gồm" so với "cách nó được xác nhận"). Trường hợp cụ thể này ở đây được xây dựng thêm trong cuốn sách Clean Code : " Các đối tượng ẩn dữ liệu của họ đằng sau sự trừu tượng và phơi bày các chức năng hoạt động trên dữ liệu đó. Cấu trúc dữ liệu phơi bày dữ liệu của họ và không có chức năng có ý nghĩa. " - ZipCodesẽ là một "cấu trúc dữ liệu" và ZipCodeHelpermột "đối tượng". Trong mọi trường hợp, tôi nghĩ rằng chúng tôi đồng ý rằng chúng ta không nên truyền kết nối web cho nhà xây dựng ZipCode.
R. Schmitz

9
Sử dụng một nguyên thủy là IMHO hợp lý trong trường hợp không có xác nhận hoặc logic khác tùy thuộc vào loại cụ thể này. => Tôi không đồng ý. Ngay cả khi tất cả các giá trị là hợp lệ, tôi vẫn sẽ truyền đạt ngữ nghĩa cho ngôn ngữ hơn là sử dụng nguyên thủy. Nếu một hàm có thể được gọi theo kiểu nguyên thủy không phù hợp với cách sử dụng ngữ nghĩa hiện tại của nó, thì nó không phải là kiểu nguyên thủy, nó phải là một kiểu thích hợp chỉ có các hàm hợp lý được xác định. (Ví dụ: sử dụng intlàm ID cho phép nhân ID với ID ...)
Matthieu M.

@ R.Schmitz Tôi nghĩ rằng mã ZIP là một ví dụ tồi cho sự khác biệt mà bạn đang thực hiện. Một cái gì đó thay đổi thường có thể là một ứng cử viên cho các lớp FooFooValidatorlớp riêng biệt . Chúng ta có thể có một ZipCodelớp xác nhận định dạng và một lớp ZipCodeValidatorđánh vào một số dịch vụ Web để kiểm tra xem một định dạng chính xác ZipCodecó thực sự hiện hành không. Chúng tôi biết rằng mã ZIP thay đổi. Nhưng thực tế, chúng ta sẽ có một danh sách các mã ZIP hợp lệ được gói gọn trong ZipCodehoặc trong một số cơ sở dữ liệu cục bộ.
Không có

55

Nếu có thể làm:

new ZipCode("totally invalid zip code");

Và hàm tạo cho ZipCode thực hiện:

ZipCodeHelper.validate("totally invalid zip code");

Sau đó, bạn đã phá vỡ đóng gói và thêm một phụ thuộc khá ngớ ngẩn vào lớp ZipCode. Nếu nhà xây dựng không gọi ZipCodeHelper.validate(...)thì bạn đã tách logic trên đảo của mình mà không thực sự thực thi nó. Bạn có thể tạo mã zip không hợp lệ.

Các validatephương pháp phải là một phương pháp tĩnh trên lớp mã bưu điện. Bây giờ kiến ​​thức về mã zip "hợp lệ" được gói cùng với lớp ZipCode. Cho rằng các ví dụ mã của bạn trông giống như Java, hàm tạo của ZipCode sẽ đưa ra một ngoại lệ nếu định dạng không chính xác được đưa ra:

public class ZipCode {
    private String zipCode;

    public ZipCode(string zipCode) {
        if (!validate(zipCode))
            throw new IllegalFormatException("Invalid zip code");

        this.zipCode = zipCode;
    }

    public static bool validate(String zipCode) {
        // logic to check format
    }

    @Override
    public String toString() {
        return zipCode;
    }
}

Hàm tạo kiểm tra định dạng và đưa ra một ngoại lệ, do đó ngăn không cho mã zip không hợp lệ được tạo và validatephương thức tĩnh có sẵn cho các mã khác để logic kiểm tra định dạng được gói gọn trong lớp ZipCode.

Không có "yo-yo" trong biến thể này của lớp ZipCode. Nó chỉ được gọi là lập trình hướng đối tượng thích hợp.


Chúng tôi cũng sẽ bỏ qua việc quốc tế hóa ở đây, có thể cần một lớp khác gọi là ZipCodeFormat hoặc PostalService (ví dụ PostalService.isValidPostalCode (...), PostalService.parsePostalCode (...), v.v.).


28
Lưu ý: Ưu điểm chính với cách tiếp cận của @Greg Burkhardt ở đây là nếu ai đó đưa cho bạn một đối tượng ZipCode, bạn có thể tin tưởng rằng nó chứa một chuỗi hợp lệ mà không phải kiểm tra lại, vì kiểu của nó và thực tế là nó được xây dựng thành công mang lại cho bạn sự đảm bảo đó Thay vào đó, nếu bạn chuyển các chuỗi xung quanh, bạn có thể cảm thấy cần phải "xác nhận xác thực (zipCode)" tại các vị trí khác nhau trong mã của mình để đảm bảo rằng bạn có mã zip hợp lệ, nhưng với đối tượng ZipCode được xây dựng thành công, bạn có thể tin tưởng rằng nội dung của nó là hợp lệ mà không cần phải kiểm tra lại.
Một số chàng trai

3
@ R.Schmitz: ZipCode.validatePhương thức này là kiểm tra trước có thể được thực hiện trước khi gọi một hàm tạo ném ngoại lệ.
Greg Burghardt

10
@ R. trả về null nếu không thành công và nếu không thì xây dựng một đối tượng ZipCode và trả về nó. Người gọi sẽ luôn luôn phải kiểm tra giá trị trả về null, tất nhiên. Mặt khác, nếu bạn có thói quen, ví dụ, luôn luôn xác nhận hợp lệ (regex? Xác thực? V.v.) trước khi xây dựng ZipCode, ngoại lệ có thể không quá khó chịu trong thực tế.
Một số chàng trai

11
Một chức năng xuất xưởng trả về <ZipCode> tùy chọn cũng là một khả năng. Sau đó, người gọi không có lựa chọn nào khác ngoài việc xử lý rõ ràng sự thất bại có thể xảy ra của chức năng xuất xưởng. Bất kể, trong cả hai trường hợp, lỗi sẽ được phát hiện ở đâu đó gần nơi nó được tạo ra thay vì có thể muộn hơn nhiều, bởi mã máy khách cách xa vấn đề ban đầu.
Một số chàng trai

6
Bạn không thể xác thực ZipCode một cách độc lập, vì vậy đừng. Bạn thực sự cần đối tượng Quốc gia để tra cứu các quy tắc xác thực ZipCode / PostCode.
Joshua

11

Nếu bạn vật lộn rất nhiều với câu hỏi này, có lẽ ngôn ngữ bạn sử dụng không phải là công cụ phù hợp cho công việc? Loại "nguyên thủy gõ tên miền" này rất dễ thể hiện trong ví dụ, F #.

Ở đó bạn có thể, ví dụ, viết:

type ZipCode = ZipCode of string
type Town = Town of string

type Adress = {
  zipCode: ZipCode
  town: Town
  //etc
}

let adress1 = {
  zipCode = ZipCode "90210"
  town = Town "Beverly Hills"
}

let faultyAdress = {
  zipCode = "12345"  // <-Compiler error
  town = adress1.zipCode // <- Compiler error
}

Điều này thực sự hữu ích để tránh các lỗi phổ biến, như so sánh id của các thực thể khác nhau. Và vì các kiểu nguyên thủy được gõ này nhẹ hơn nhiều so với lớp C # hoặc lớp Java, nên cuối cùng bạn sẽ thực sự sử dụng chúng.


Thú vị - nó sẽ trông như thế nào nếu bạn muốn thực thi xác nhận ZipCode?
Hulk

4
@Hulk Bạn có thể viết kiểu OO trong F # và biến các kiểu thành các lớp. Tuy nhiên, tôi thích kiểu chức năng hơn, khai báo kiểu với kiểu ZipCode = private ZipCode của chuỗi và thêm mô-đun ZipCode với hàm tạo. Có một số ví dụ ở đây: gist.github.com/swlaschin/54cfff886669ccab895a
Guran

@ Bent-Tranberg Cảm ơn bạn đã chỉnh sửa. Bạn đã đúng, một kiểu viết tắt đơn giản không cung cấp bảo mật kiểu thời gian biên dịch.
Guran

Nếu bạn được gửi bình luận đầu tiên của tôi, rằng tôi đã xóa, lý do là lần đầu tiên tôi hiểu nhầm nguồn của bạn. Tôi đã không đọc nó đủ cẩn thận. Khi tôi cố gắng biên dịch nó, cuối cùng tôi nhận ra rằng bạn thực sự đang cố gắng chứng minh chính xác điều này, vì vậy sau đó tôi quyết định chỉnh sửa để làm cho đúng.
Bent Tranberg

Vâng. Nguồn ban đầu của tôi là hợp lệ, không may, bao gồm cả ví dụ được CUNG CẤP là không hợp lệ. Đừng! Nên hav chỉ liên kết với Wlaschin thay vì tự gõ mã :) fsharpforfunandprofit.com/posts/ Kẻ
Guran

6

Câu trả lời hoàn toàn phụ thuộc vào những gì bạn thực sự muốn làm với mã ZIP. Đây là hai khả năng cực kỳ:

(1) Tất cả các địa chỉ được đảm bảo ở một quốc gia. Không có ngoại lệ nào cả. (Ví dụ: không có khách hàng nước ngoài hoặc không có nhân viên có địa chỉ riêng ở nước ngoài khi họ đang làm việc cho một khách hàng nước ngoài.) Quốc gia này có mã ZIP và họ có thể sẽ không bao giờ gặp vấn đề nghiêm trọng chẳng hạn như "hiện tại là D4B 6N2, nhưng điều này thay đổi cứ sau 2 tuần"). Mã ZIP không chỉ được sử dụng để đánh địa chỉ mà còn xác thực thông tin thanh toán hoặc các mục đích tương tự. - Trong những trường hợp này, một lớp mã ZIP có rất nhiều ý nghĩa.

(2) Địa chỉ có thể ở hầu hết mọi quốc gia, do đó, hàng chục hoặc hàng trăm địa chỉ địa chỉ có hoặc không có mã ZIP (và với hàng ngàn trường hợp ngoại lệ kỳ lạ và trường hợp đặc biệt) có liên quan. Mã "ZIP" thực sự chỉ được yêu cầu nhắc nhở mọi người từ các quốc gia nơi mã ZIP được sử dụng không quên cung cấp mã của họ. Các địa chỉ chỉ được sử dụng để nếu ai đó mất quyền truy cập vào tài khoản của họ và họ có thể chứng minh tên và địa chỉ của mình, quyền truy cập sẽ được khôi phục. - Trong những trường hợp này, các lớp mã ZIP cho tất cả các quốc gia có liên quan sẽ là một nỗ lực to lớn. May mắn là họ không cần thiết chút nào.


3

Các câu trả lời khác đã nói về mô hình miền OO và sử dụng loại phong phú hơn để thể hiện giá trị của bạn.

Tôi không đồng ý, đặc biệt là đưa ra mã ví dụ bạn đã đăng.

Nhưng tôi cũng tự hỏi nếu điều đó thực sự trả lời tiêu đề của câu hỏi của bạn.

Hãy xem xét kịch bản sau đây (được lấy từ một dự án thực tế mà tôi đang thực hiện):

Bạn có một ứng dụng từ xa trên một thiết bị hiện trường nói chuyện với máy chủ trung tâm của bạn. Một trong các trường DB cho mục nhập thiết bị là mã zip cho địa chỉ mà thiết bị trường đang ở. Bạn không quan tâm đến mã zip (hoặc bất kỳ phần còn lại của địa chỉ cho vấn đề đó). Tất cả những người quan tâm đến nó đều ở phía bên kia của ranh giới HTTP: bạn tình cờ là nguồn sự thật duy nhất cho dữ liệu. Nó không có chỗ trong mô hình miền của bạn. Bạn chỉ cần ghi lại nó, xác nhận nó, lưu trữ nó và theo yêu cầu xáo trộn nó trong một blob JSON đến các điểm khác.

Trong kịch bản này, thực hiện bất kỳ điều gì ngoài việc xác thực tính năng chèn với ràng buộc regex SQL (hoặc tương đương ORM của nó) có lẽ là quá mức cần thiết của giống YAGNI.


6
Ràng buộc regex SQL của bạn có thể được xem là một loại đủ điều kiện - trong cơ sở dữ liệu của bạn, mã Zip không được lưu trữ dưới dạng "VarChar" mà là "VarChar bị ràng buộc bởi quy tắc này". Trong một số DBMS, bạn có thể dễ dàng đặt loại + ràng buộc tên đó dưới dạng "loại miền" có thể sử dụng lại và chúng tôi quay lại vị trí được đề xuất để cung cấp cho dữ liệu một loại có ý nghĩa. Tôi đồng ý với câu trả lời của bạn về nguyên tắc, nhưng đừng nghĩ rằng ví dụ đó phù hợp; một ví dụ tốt hơn sẽ là nếu dữ liệu của bạn là "dữ liệu cảm biến thô" và loại có ý nghĩa nhất là "mảng byte" bởi vì bạn không biết dữ liệu đó có nghĩa gì.
IMSoP

@IMSoP điểm thú vị. Mặc dù không chắc chắn tôi đồng ý: bạn có thể xác thực mã zip chuỗi trong Java (hoặc bất kỳ ngôn ngữ nào khác) bằng biểu thức chính quy nhưng vẫn xử lý nó dưới dạng chuỗi thay vì loại phong phú hơn. Tùy thuộc vào logic tên miền, có thể cần phải thao tác thêm (ví dụ: đảm bảo rằng mã zip khớp với trạng thái, điều gì đó sẽ khó / không thể xác thực bằng regex).
Jared Smith

Bạn có thể , nhưng ngay sau khi bạn làm như vậy, bạn đang gán cho nó một số hành vi cụ thể theo tên miền và đó chính xác là những gì các bài báo được trích dẫn sẽ dẫn đến việc tạo ra một loại tùy chỉnh. Câu hỏi không phải là liệu bạn có thể làm điều đó theo phong cách này hay phong cách khác, mà là liệu bạn có nên , giả sử ngôn ngữ lập trình của bạn mang lại cho bạn sự lựa chọn.
IMSoP

Bạn có thể mô hình hóa một thứ như một RegexValidatedString, chứa chính chuỗi và biểu thức chính được sử dụng để xác thực nó. Nhưng trừ khi mọi trường hợp có một regex duy nhất (có thể nhưng không thể), điều này có vẻ hơi ngớ ngẩn và lãng phí bộ nhớ (và có thể là thời gian biên dịch regex). Vì vậy, bạn hoặc đặt regex vào một bảng riêng biệt và để lại một khóa tra cứu trong mỗi trường hợp để tìm nó (điều này được cho là tồi tệ hơn do sự gián tiếp) hoặc bạn tìm cách lưu trữ nó một lần cho mỗi loại chia sẻ giá trị chung đó - - ví dụ. một trường tĩnh trên một loại tên miền, hoặc phương thức tương đương, như IMSoP đã nói.
Miral

2

Sự ZipCodetrừu tượng chỉ có thể có ý nghĩa nếu Addresslớp của bạn không có TownNametài sản. Mặt khác, bạn có một nửa trừu tượng: mã zip chỉ định thị trấn, nhưng hai bit thông tin liên quan này được tìm thấy trong các lớp khác nhau. Nó không hoàn toàn có ý nghĩa.

Tuy nhiên, ngay cả khi đó, nó vẫn không phải là một ứng dụng chính xác (hay đúng hơn là giải pháp cho) nỗi ám ảnh nguyên thủy; mà theo tôi hiểu thì chủ yếu tập trung vào hai điều:

  1. Sử dụng các giá trị nguyên thủy làm giá trị đầu vào (hoặc thậm chí đầu ra) của một phương thức, đặc biệt là khi cần một bộ sưu tập các nguyên hàm.
  2. Các lớp phát triển các thuộc tính bổ sung theo thời gian mà không bao giờ xem xét liệu một số trong số chúng có nên được nhóm thành một lớp con của riêng chúng hay không.

Trường hợp của bạn là không. Địa chỉ là một khái niệm được xác định rõ ràng với các thuộc tính rõ ràng cần thiết (đường phố, số, zip, thị trấn, tiểu bang, quốc gia, ...). Có rất ít hoặc không có lý do để phá vỡ dữ liệu này vì nó có một trách nhiệm duy nhất : chỉ định một vị trí trên Trái đất. Một địa chỉ yêu cầu tất cả các lĩnh vực này để có ý nghĩa. Một nửa địa chỉ là vô nghĩa.

Đây là cách bạn biết rằng bạn không cần phải chia nhỏ hơn nữa: phá vỡ nó thêm nữa sẽ làm mất đi ý định chức năng của Addresslớp. Tương tự, bạn không cần một Namelớp con được sử dụng trong Personlớp, trừ khi Name(không có người nào đính kèm) là một khái niệm có ý nghĩa trong miền của bạn. Mà nó (thường) không. Tên được sử dụng để xác định người, chúng thường không có giá trị riêng.


1
@RikD: Từ câu trả lời: "bạn không cần Namesử dụng một lớp con trong Personlớp, trừ khi Tên (không có người được đính kèm) là một khái niệm có ý nghĩa trong miền của bạn ." Khi bạn có xác thực tùy chỉnh cho tên, tên đó đã trở thành một khái niệm có ý nghĩa trong miền của bạn; mà tôi đã đề cập rõ ràng như là một trường hợp sử dụng hợp lệ để sử dụng một kiểu con. Thứ hai, để xác thực mã zip, bạn đang đưa ra các giả định bổ sung, chẳng hạn như mã zip cần tuân theo định dạng của một quốc gia nhất định. Bạn đang giới thiệu một chủ đề rộng hơn nhiều so với mục đích của câu hỏi của OP.
Flater

5
" Địa chỉ là một khái niệm được xác định rõ ràng với các thuộc tính rõ ràng cần thiết (đường phố, số, zip, thị trấn, tiểu bang, quốc gia). " - Điều đó hoàn toàn sai. Để biết cách giải quyết vấn đề này, hãy xem biểu mẫu địa chỉ của Amazon.
R. Schmitz

4
@Flater Tôi sẽ không trách bạn vì đã không đọc danh sách đầy đủ về sự giả dối, bởi vì nó khá dài, nhưng theo nghĩa đen nó chứa "Địa chỉ sẽ có một đường phố", "Một địa chỉ yêu cầu cả thành phố và quốc gia", "Một địa chỉ sẽ có một mã bưu điện ", v.v., trái với những gì câu trích dẫn nói.
R. Schmitz

8
@GregBurghardt "Mã zip giả định Dịch vụ Bưu chính Hoa Kỳ và bạn có thể lấy tên của thị trấn từ mã zip. Thành phố có thể có nhiều mã zip, nhưng mỗi mã zip chỉ được gắn với 1 thành phố." Điều này không đúng nói chung. Tôi có một mã zip được sử dụng chủ yếu cho một thành phố lân cận nhưng nơi cư trú của tôi không nằm ở đó. Mã bưu điện không phải lúc nào cũng phù hợp với ranh giới chính phủ. Ví dụ: 42223 chứa các hạt từ cả TN và KY .
JimmyJames

2
Ở Áo tồn tại một thung lũng chỉ có thể truy cập từ Đức ( en.wikipedia.org/wiki/Kleinwalsertal ). Có một hiệp ước đặc biệt cho khu vực này, trong số những điều khác, cũng bao gồm các địa chỉ trong khu vực này có cả mã bưu chính của Áo và Đức. Vì vậy, nói chung, bạn thậm chí không thể cho rằng một địa chỉ chỉ có một mã bưu chính hợp lệ duy nhất;)
Hulk

1

Từ bài viết:

Tổng quát hơn, vấn đề yo-yo cũng có thể đề cập đến bất kỳ tình huống nào mà một người phải tiếp tục lật giữa các nguồn thông tin khác nhau để hiểu một khái niệm.

Mã nguồn được đọc thường xuyên hơn nhiều so với nó được viết. Do đó, vấn đề yo-yo, về việc phải chuyển đổi giữa nhiều tập tin là một mối quan tâm.

Tuy nhiên, không , vấn đề yo-yo cảm thấy phù hợp hơn nhiều khi xử lý các mô-đun hoặc các lớp phụ thuộc lẫn nhau sâu sắc (gọi qua lại với nhau). Đó là một loại ác mộng đặc biệt để đọc, và có khả năng là điều mà người giải quyết vấn đề yo-yo đã nghĩ đến.

Tuy nhiên - , tránh quá nhiều lớp trừu tượng là quan trọng!

Tất cả các khái niệm trừu tượng không tầm thường, ở một mức độ nào đó, đều bị rò rỉ. - Luật trừu tượng rò rỉ.

Ví dụ, tôi không đồng ý với giả định được đưa ra trong câu trả lời của mmmaaa rằng "bạn không cần phải yo-yo để [(truy cập)] lớp ZipCode để hiểu lớp Địa chỉ". Kinh nghiệm của tôi là bạn làm - ít nhất là vài lần đầu tiên bạn đọc mã. Tuy nhiên, như những người khác đã lưu ý, có những lúc một ZipCodelớp học phù hợp.

YAGNI (Ya Không phải là Gonna Cần It) là một mô hình tốt hơn để làm theo để tránh mã Lasagna (mã với quá nhiều lớp) - trừu tượng, chẳng hạn như các loại và các lớp học đang có để giúp các lập trình viên, và không nên được sử dụng, trừ khi họ một sự trợ giúp.

Cá nhân tôi nhắm đến "lưu dòng mã" (và tất nhiên là "lưu tệp / mô-đun / lớp" có liên quan, v.v.). Tôi tin rằng có một số người sẽ áp dụng cho tôi biểu tượng của "nỗi ám ảnh nguyên thủy" - Tôi thấy điều quan trọng hơn là có mã dễ lý luận hơn là lo lắng về nhãn, mẫu và chống mẫu. Sự lựa chọn chính xác khi nào tạo một hàm, một mô-đun / tệp / lớp hoặc đặt một hàm ở một vị trí chung là rất tình huống. Tôi nhắm mục tiêu đại khái cho 3 - 100 chức năng dòng, 80-500 tệp dòng và "1, 2, n" cho mã thư viện có thể sử dụng lại ( SLOC - không bao gồm nhận xét hoặc bản tóm tắt; Tôi thường muốn ít nhất 1 SLOC tối thiểu cho mỗi dòng bắt buộc bản mẫu).

Hầu hết các mô hình tích cực đã phát sinh từ các nhà phát triển làm chính xác điều đó, khi họ cần chúng . Điều quan trọng hơn nhiều là học cách viết mã có thể đọc được hơn là cố gắng áp dụng các mẫu mà không có cùng một vấn đề để giải quyết. Bất kỳ nhà phát triển giỏi nào cũng có thể thực hiện mô hình nhà máy mà không cần nhìn thấy nó trước đây trong trường hợp không phổ biến, nơi nó phù hợp với vấn đề của họ. Tôi đã sử dụng mẫu nhà máy, mẫu quan sát viên và có lẽ hàng trăm người bên cạnh, mà không biết tên của họ (nghĩa là có "mẫu gán biến" không?). Đối với một thử nghiệm thú vị - hãy xem có bao nhiêu mẫu GoF được tích hợp vào ngôn ngữ JS - tôi đã ngừng đếm sau khoảng 12-15 trở lại năm 2009. Ví dụ, mẫu Factory đơn giản như trả về một đối tượng từ một hàm tạo của JS - không cần một WidgetFactory.

Vì vậy - , đôi khi ZipCode là một lớp học tốt. Tuy nhiên, không , vấn đề yo-yo không liên quan chặt chẽ.


0

Vấn đề yo-yo chỉ liên quan nếu bạn phải lật qua lại. Điều đó được gây ra bởi một hoặc hai điều (đôi khi cả hai):

  1. Đặt tên xấu. ZipCode có vẻ ổn, ZoneImproferencePlanCode sẽ yêu cầu hầu hết mọi người nhìn (và một số ít sẽ không ấn tượng).
  2. Khớp nối không phù hợp. Giả sử bạn lớp ZipCode có tra cứu mã vùng. Bạn có thể nghĩ nó có ý nghĩa bởi vì nó tiện dụng, nhưng nó không thực sự liên quan đến ZipCode, và đặt nó vào đó có nghĩa là bây giờ mọi người không biết đi đâu để tìm thứ gì.

Nếu bạn có thể nhìn vào tên và có ý tưởng hợp lý về những gì nó làm, và các phương thức và thuộc tính thực hiện những điều hợp lý rõ ràng, bạn không cần phải xem mã, bạn có thể sử dụng nó. Đó là toàn bộ điểm của các lớp ở vị trí đầu tiên, đó là những đoạn mã mô-đun có thể được sử dụng và phát triển một cách cô lập. Nếu bạn phải xem xét bất cứ điều gì khác ngoài API cho lớp để xem những gì nó làm, thì ít nhất đó là một phần thất bại.


-1

Hãy nhớ rằng, không có viên đạn bạc. Nếu bạn đang viết một ứng dụng cực kỳ đơn giản cần được thu thập thông tin nhanh, thì một chuỗi đơn giản có thể thực hiện công việc. Tuy nhiên, trong 98% số lần, một Đối tượng Giá trị như được mô tả bởi Eric Evans trong DDD, sẽ là sự phù hợp hoàn hảo. Bạn có thể dễ dàng thấy tất cả các lợi ích Đối tượng giá trị cung cấp bằng cách đọc xung quanh.

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.