Có bất kỳ lý do để sử dụng các lớp dữ liệu cũ đơn giản dữ liệu cũ không?


43

Trong mã kế thừa, tôi thỉnh thoảng thấy các lớp không có gì ngoài các hàm bao cho dữ liệu. cái gì đó như:

class Bottle {
   int height;
   int diameter;
   Cap capType;

   getters/setters, maybe a constructor
}

Sự hiểu biết của tôi về OO là các lớp là các cấu trúc cho dữ liệu và các phương thức hoạt động trên dữ liệu đó. Điều này dường như để loại trừ các đối tượng của loại này. Đối với tôi họ chẳng hơn gì structsvà đánh bại mục đích của OO. Tôi không nghĩ nó nhất thiết phải xấu, mặc dù nó có thể là mùi mã.

Có một trường hợp mà các đối tượng như vậy sẽ là cần thiết? Nếu điều này được sử dụng thường xuyên, nó có làm cho thiết kế nghi ngờ?


1
Điều này không hoàn toàn trả lời câu hỏi của bạn nhưng dù sao có vẻ có liên quan: stackoverflow.com/questions/36701/struct-like-objects-in-java
Adam Lear

2
Tôi nghĩ thuật ngữ bạn đang tìm kiếm là POD (Dữ liệu cũ đơn giản).
Gaurav

9
Đây là một ví dụ điển hình của lập trình có cấu trúc. Không hẳn là xấu, chỉ là không hướng đối tượng.
Konrad Rudolph

1
không nên tràn vào ngăn xếp này?
Muad'Dib

7
@ Muad'Dib: về mặt kỹ thuật, đó về lập trình viên. Trình biên dịch của bạn không quan tâm nếu bạn sử dụng các cấu trúc dữ liệu cũ đơn giản. CPU của bạn có thể thích nó (theo cách "Tôi thích mùi dữ liệu mới từ bộ đệm"). Đó là những người bị treo lên "điều này làm cho phương pháp của tôi kém tinh khiết hơn?" Câu hỏi.
Shog9

Câu trả lời:


67

Chắc chắn không phải là xấu xa và không phải là một mùi mã trong tâm trí của tôi. Container dữ liệu là một công dân OO hợp lệ. Đôi khi bạn muốn gói gọn các thông tin liên quan lại với nhau. Tốt hơn nhiều là có một phương pháp như

public void DoStuffWithBottle(Bottle b)
{
    // do something that doesn't modify Bottle, so the method doesn't belong
    // on that class
}

hơn

public void DoStuffWithBottle(int bottleHeight, int bottleDiameter, Cap capType)
{
}

Sử dụng một lớp cũng cho phép bạn thêm một tham số bổ sung vào Chai mà không sửa đổi mọi người gọi của DoStuffWithBottle. Và bạn có thể phân lớp Chai và tăng thêm khả năng đọc và tổ chức mã của bạn, nếu cần.

Ví dụ, cũng có các đối tượng dữ liệu đơn giản có thể được trả về do truy vấn cơ sở dữ liệu. Tôi tin rằng thuật ngữ cho họ trong trường hợp đó là "Đối tượng truyền dữ liệu".

Trong một số ngôn ngữ cũng có những cân nhắc khác. Ví dụ, trong các lớp C # và các cấu trúc hoạt động khác nhau, vì các cấu trúc là một loại giá trị và các lớp là các loại tham chiếu.


25
Không DoStuffWithphải là một phương pháp của các Bottlelớp trong OOP (và có lẽ hầu hết sẽ không thay đổi, quá). Những gì bạn đã viết ở trên không phải là một mô hình tốt trong ngôn ngữ OO (trừ khi bạn đang can thiệp vào API kế thừa). Đó , tuy nhiên, một thiết kế có giá trị trong một môi trường phi OO.
Konrad Rudolph

11
@Javier: Vậy thì Java cũng không phải là câu trả lời hay nhất. Sự nhấn mạnh của Java đối với OO là quá sức, ngôn ngữ về cơ bản là không tốt với bất cứ điều gì khác.
Konrad Rudolph

11
@ John: Tất nhiên tôi đã đơn giản hóa. Nhưng nói chung, các đối tượng trong trạng thái đóng gói OO , không phải dữ liệu. Đây là một sự khác biệt tốt nhưng quan trọng. Quan điểm của OOP chính xác là không có nhiều dữ liệu xung quanh. Nó đang gửi tin nhắn giữa các trạng thái tạo ra một trạng thái mới. Tôi không thấy cách bạn có thể gửi tin nhắn đến hoặc từ một đối tượng không có phương thức. (Và đây là định nghĩa ban đầu của OOP nên tôi sẽ không xem xét nó là thiếu sót.)
Konrad Rudolph

13
@Konrad Rudolph: Đây là lý do tại sao tôi đưa ra nhận xét rõ ràng bên trong phương thức. Tôi đồng ý rằng các phương thức ảnh hưởng đến các thể hiện của Chai nên đi trong lớp đó. Nhưng nếu một đối tượng khác cần sửa đổi trạng thái của nó dựa trên thông tin trong Chai, thì tôi nghĩ thiết kế của tôi sẽ khá hợp lệ.
Adam Lear

10
@Konrad, tôi không đồng ý rằng doStuffWithBottle nên đi trong lớp chai. Tại sao một chai nên biết làm thế nào với chính nó? doStuffWithBottle chỉ ra rằng một cái gì đó khác sẽ làm một cái gì đó với một cái chai. Nếu chai có trong đó, đó sẽ là khớp nối chặt chẽ. Tuy nhiên, nếu lớp Chai có phương thức isFull (), điều đó hoàn toàn phù hợp.
Nemi

25

Các lớp dữ liệu có giá trị trong một số trường hợp. DTO là một ví dụ điển hình được đề cập bởi Anna Lear. Tuy nhiên, nói chung, bạn nên coi chúng là hạt giống của một lớp mà các phương thức chưa được nảy mầm. Và nếu bạn đang chạy vào rất nhiều trong số chúng trong mã cũ, hãy coi chúng như một mùi mã mạnh. Chúng thường được sử dụng bởi các lập trình viên C / C ++ cũ, những người chưa bao giờ thực hiện chuyển đổi sang lập trình OO và là một dấu hiệu của lập trình thủ tục. Dựa vào getters và setters mọi lúc (hoặc tệ hơn nữa, về việc truy cập trực tiếp của các thành viên không riêng tư) có thể khiến bạn gặp rắc rối trước khi bạn biết điều đó. Hãy xem xét một ví dụ về một phương pháp bên ngoài cần thông tin từ Bottle.

Đây Bottlelà một lớp dữ liệu):

void selectShippingContainer(Bottle bottle) {
    if (bottle.getDiameter() > MAX_DIMENSION || bottle.getHeight() > MAX_DIMENSION ||
            bottle.getCapType() == Cap.FANCY_CAP ) {
        shippingContainer = WOODEN_CRATE;
    } else {
        shippingContainer = CARDBOARD_BOX;
    }
}

Ở đây chúng tôi đã đưa ra Bottlemột số hành vi):

void selectShippingContainer(Bottle bottle) {
    if (bottle.isBiggerThan(MAX_DIMENSION) || bottle.isFragile()) {
        shippingContainer = WOODEN_CRATE;
    } else {
        shippingContainer = CARDBOARD_BOX;
    }
}

Phương thức đầu tiên vi phạm nguyên tắc Nói-Đừng-Hỏi, và bằng cách giữ Bottleim lặng, chúng tôi đã để cho kiến ​​thức ngầm về các chai, chẳng hạn như điều gì làm cho một người yếu đuối (cái Cap), rơi vào logic bên ngoài Bottlelớp học. Bạn phải luôn cố gắng để ngăn chặn loại 'rò rỉ' này khi bạn thường xuyên dựa vào getters.

Phương pháp thứ hai Bottlechỉ yêu cầu những gì nó cần để thực hiện công việc của mình và rời đi Bottleđể quyết định xem nó có dễ vỡ hay lớn hơn một kích thước nhất định hay không. Kết quả là một sự kết hợp lỏng lẻo hơn nhiều giữa phương pháp và việc triển khai của Chai. Một tác dụng phụ dễ chịu là phương pháp sạch hơn và biểu cảm hơn.

Bạn sẽ hiếm khi sử dụng nhiều trường này của một đối tượng mà không viết một số logic phải nằm trong lớp với các trường đó. Chỉ ra logic đó là gì và sau đó di chuyển nó đến nơi nó thuộc về.


1
Không thể tin câu trả lời này không có phiếu bầu (tốt, bạn có ngay bây giờ). Đây có thể là một ví dụ đơn giản, nhưng khi OO bị lạm dụng đủ, bạn sẽ có các lớp dịch vụ biến thành ác mộng chứa hàng tấn chức năng đáng lẽ phải được gói gọn trong các lớp.
Alb

"bởi các lập trình viên C / C ++ cũ, những người chưa bao giờ thực hiện chuyển đổi (sic) sang OO"? Các lập trình viên C ++ thường là OO xinh đẹp, vì đó là ngôn ngữ OO, tức là toàn bộ quan điểm sử dụng C ++ thay vì C.
nappyfalcon

7

Nếu đây là thứ bạn cần, thì tốt, nhưng làm ơn, làm ơn, làm ơn làm đi

public class Bottle {
    public int height;
    public int diameter;
    public Cap capType;

    public Bottle(int height, int diameter, Cap capType) {
        this.height = height;
        this.diameter = diameter;
        this.capType = capType;
    }
}

thay vì một cái gì đó như

public class Bottle {
    private int height;
    private int diameter;
    private Cap capType;

    public Bottle(int height, int diameter, Cap capType) {
        this.height = height;
        this.diameter = diameter;
        this.capType = capType;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getDiameter() {
        return diameter;
    }

    public void setDiameter(int diameter) {
        this.diameter = diameter;
    }

    public Cap getCapType() {
        return capType;
    }

    public void setCapType(Cap capType) {
        this.capType = capType;
    }
}

Xin vui lòng.


14
Vấn đề duy nhất với điều này là không có xác nhận. Bất kỳ logic nào về những gì một Chai hợp lệ là trong lớp Chai. Tuy nhiên, bằng cách sử dụng triển khai được đề xuất của bạn, tôi có thể có một chai có chiều cao và đường kính âm - không có cách nào để thực thi bất kỳ quy tắc kinh doanh nào trên đối tượng mà không xác nhận mỗi khi đối tượng được sử dụng. Bằng cách sử dụng phương thức thứ hai, tôi có thể đảm bảo rằng nếu tôi có một đối tượng Chai, nó đã và sẽ luôn là một đối tượng Chai hợp lệ theo hợp đồng của tôi.
Thomas Owens

6
Đó là một lĩnh vực mà .NET có lợi thế hơn một chút so với các thuộc tính, vì bạn có thể thêm một trình truy cập thuộc tính với logic xác thực, với cùng một cú pháp như thể bạn đang truy cập vào một trường. Bạn cũng có thể định nghĩa một thuộc tính nơi các lớp có thể nhận giá trị thuộc tính, nhưng không đặt nó.
JohnL

3
@ user9521 Nếu bạn chắc chắn rằng mã của bạn sẽ không gây ra lỗi nghiêm trọng với các giá trị "xấu", thì hãy sử dụng phương pháp của bạn. Tuy nhiên, nếu bạn cần xác nhận thêm hoặc khả năng sử dụng tải lười biếng hoặc kiểm tra khác khi dữ liệu được đọc hoặc ghi, sau đó sử dụng getters và setters rõ ràng. Cá nhân tôi có xu hướng giữ các biến của mình ở chế độ riêng tư và sử dụng getters và setters để thống nhất. Bằng cách này, tất cả các biến của tôi đều được xử lý như nhau, bất kể xác nhận và / hoặc các kỹ thuật "nâng cao" khác.
Jonathan

2
Ưu điểm của việc sử dụng hàm tạo là nó làm cho lớp dễ dàng hơn nhiều. Điều này rất cần thiết nếu bạn muốn viết mã đa luồng.
Fortyrunner

7
Tôi sẽ làm cho các lĩnh vực cuối cùng bất cứ khi nào có thể. IMHO Tôi sẽ có các trường ưa thích là cuối cùng theo mặc định và có một từ khóa cho các trường có thể thay đổi. ví dụ: var
Peter Lawrey

6

Như @Anna đã nói, chắc chắn không xấu xa. Chắc chắn bạn có thể đặt các hoạt động (phương thức) vào các lớp, nhưng chỉ khi bạn muốn . Bạn không cần phải làm vậy.

Cho phép tôi hiểu một chút về ý tưởng rằng bạn phải đưa các hoạt động vào các lớp, cùng với ý tưởng rằng các lớp là trừu tượng. Trong thực tế, điều này khuyến khích các lập trình viên

  1. Tạo nhiều lớp hơn mức cần thiết (cấu trúc dữ liệu dự phòng). Khi một cấu trúc dữ liệu chứa nhiều thành phần hơn mức tối thiểu cần thiết, nó không được chuẩn hóa và do đó chứa các trạng thái không nhất quán. Nói cách khác, khi nó bị thay đổi, nó cần được thay đổi ở nhiều nơi để duy trì sự nhất quán. Việc không thực hiện tất cả các thay đổi phối hợp làm cho nó không nhất quán và là một lỗi.

  2. Giải quyết vấn đề 1 bằng cách đưa vào các phương thức thông báo , để nếu phần A được sửa đổi, nó sẽ cố gắng truyền các thay đổi cần thiết cho các phần B và C. Đây là lý do chính tại sao nên sử dụng các phương thức truy cập get-and-set. Vì đây là cách thực hành được khuyến nghị, nên nó xuất hiện để giải thích vấn đề 1, gây ra nhiều vấn đề hơn 1 và nhiều giải pháp 2. Kết quả này không chỉ xảy ra lỗi do thực hiện không đầy đủ các thông báo, mà còn là vấn đề giảm hiệu năng của thông báo chạy trốn. Đây không phải là những tính toán vô hạn, chỉ đơn thuần là những tính toán rất dài.

Những khái niệm này được dạy là những điều tốt, thường là bởi những giáo viên chưa từng làm việc trong các ứng dụng quái vật hàng triệu câu đố với những vấn đề này.

Đây là những gì tôi cố gắng làm:

  1. Giữ dữ liệu càng chuẩn hóa càng tốt, để khi thay đổi dữ liệu được thực hiện, nó được thực hiện ở càng ít điểm mã càng tốt, để giảm thiểu khả năng vào trạng thái không nhất quán.

  2. Khi dữ liệu phải không được chuẩn hóa và không thể tránh khỏi tình trạng dư thừa, không sử dụng thông báo để cố gắng duy trì dữ liệu. Thay vào đó, chịu đựng sự không nhất quán tạm thời. Giải quyết sự không nhất quán với quét định kỳ thông qua dữ liệu bằng một quy trình chỉ thực hiện điều đó. Điều này tập trung trách nhiệm duy trì tính nhất quán, đồng thời tránh các vấn đề về hiệu suất và tính chính xác mà các thông báo dễ xảy ra. Điều này dẫn đến mã nhỏ hơn nhiều, không có lỗi và hiệu quả.


3

Loại lớp này khá hữu ích khi bạn đang xử lý các ứng dụng cỡ trung / lớn, vì một số lý do:

  • thật dễ dàng để tạo ra một số trường hợp thử nghiệm và đảm bảo dữ liệu phù hợp.
  • nó chứa tất cả các loại hành vi liên quan đến thông tin đó, vì vậy thời gian theo dõi lỗi dữ liệu được giảm
  • Sử dụng chúng nên giữ cho phương pháp args nhẹ.
  • Khi sử dụng ORM, các lớp này mang lại sự linh hoạt và nhất quán. Thêm một thuộc tính phức tạp được tính toán dựa trên thông tin đơn giản đã có trong lớp, nối lại bằng cách viết một phương thức đơn giản. Điều này khá nhanh nhẹn và hiệu quả hơn khi phải kiểm tra cơ sở dữ liệu của bạn và đảm bảo tất cả các cơ sở dữ liệu được vá với sửa đổi mới.

Vì vậy, để tóm tắt, theo kinh nghiệm của tôi, chúng thường hữu ích hơn là gây phiền nhiễu.


3

Với thiết kế trò chơi, đôi khi có 1000 cuộc gọi chức năng và người nghe sự kiện đôi khi có thể khiến nó đáng để có các lớp chỉ lưu trữ dữ liệu và có các lớp khác lặp qua tất cả các lớp chỉ có dữ liệu để thực hiện logic.


3

Đồng ý với Anna Lear,

Chắc chắn không phải là xấu xa và không phải là một mùi mã trong tâm trí của tôi. Container dữ liệu là một công dân OO hợp lệ. Đôi khi bạn muốn gói gọn các thông tin liên quan lại với nhau. Sẽ tốt hơn rất nhiều khi có một phương pháp như ...

Đôi khi mọi người quên đọc các Công ước mã hóa Java 1999, điều này cho thấy rất rõ rằng loại lập trình này là hoàn toàn tốt. Trong thực tế nếu bạn tránh nó, thì mã của bạn sẽ có mùi! (quá nhiều getters / setters)

Từ các quy ước mã Java 1999: Một ví dụ về các biến cá thể công cộng thích hợp là trường hợp lớp về cơ bản là một cấu trúc dữ liệu, không có hành vi. Nói cách khác, nếu bạn đã sử dụng một cấu trúc thay vì một lớp (nếu cấu trúc được Java hỗ trợ), thì nó phù hợp để biến các biến đối tượng của lớp thành công khai. http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177

Khi được sử dụng một cách chính xác, các POD (cấu trúc dữ liệu cũ đơn giản) tốt hơn POJO giống như POJO thường tốt hơn EJB.
http://en.wikipedia.org/wiki/Plain_Old_Data_St cấu trúc


3

Các cấu trúc có vị trí của chúng, ngay cả trong Java. Bạn chỉ nên sử dụng chúng nếu hai điều sau đây là đúng:

  • Bạn chỉ cần tổng hợp dữ liệu không có bất kỳ hành vi nào, ví dụ: truyền như một tham số
  • Nó không quan trọng một chút về loại giá trị mà dữ liệu tổng hợp có

Nếu đây là trường hợp, thì bạn nên đặt các trường công khai và bỏ qua các getters / setters. Getters và setters dù sao cũng khó hiểu và Java thật ngớ ngẩn vì không có các thuộc tính như một ngôn ngữ hữu ích. Vì đối tượng giống như cấu trúc của bạn không nên có bất kỳ phương thức nào, các trường công khai có ý nghĩa nhất.

Tuy nhiên, nếu một trong hai không áp dụng, bạn đang giao dịch với một lớp thực sự. Điều đó có nghĩa là tất cả các lĩnh vực nên riêng tư. (Nếu bạn thực sự cần một trường ở phạm vi dễ tiếp cận hơn, hãy sử dụng getter / setter.)

Để kiểm tra xem cấu trúc được cho là của bạn có hành vi hay không, hãy xem khi các trường được sử dụng. Nếu nó có vẻ vi phạm , đừng hỏi , sau đó bạn cần chuyển hành vi đó vào lớp của mình.

Nếu một số dữ liệu của bạn không nên thay đổi, thì bạn cần phải làm cho tất cả các trường đó là cuối cùng. Bạn có thể xem xét làm cho lớp học của bạn bất biến . Nếu bạn cần xác thực dữ liệu của mình, sau đó cung cấp xác thực trong setters và constructor. (Một mẹo hữu ích là xác định một setter riêng và sửa đổi trường của bạn trong lớp chỉ bằng cách sử dụng setter đó.)

Ví dụ Chai của bạn rất có thể sẽ thất bại cả hai bài kiểm tra. Bạn có thể có (mã) giống như thế này:

public double calculateVolumeAsCylinder(Bottle bottle) {
    return bottle.height * (bottle.diameter / 2.0) * Math.PI);
}

Thay vào đó nên

double volume = bottle.calculateVolumeAsCylinder();

Nếu bạn thay đổi chiều cao và đường kính, nó sẽ là cùng một chai? Chắc là không. Những người nên được cuối cùng. Là một giá trị âm ok cho đường kính? Chai của bạn phải cao hơn chiều rộng? Cap có thể là null? Không? Làm thế nào bạn xác nhận điều này? Giả sử khách hàng là ngu ngốc hoặc xấu xa. ( Không thể nói sự khác biệt. ) Bạn cần kiểm tra các giá trị này.

Đây là lớp Chai mới của bạn có thể trông như thế nào:

public class Bottle {

    private final int height, diameter;

    private Cap capType;

    public Bottle(final int height, final int diameter, final Cap capType) {
        if (diameter < 1) throw new IllegalArgumentException("diameter must be positive");
        if (height < diameter) throw new IllegalArgumentException("bottle must be taller than its diameter");

        setCapType(capType);
        this.height = height;
        this.diameter = diameter;
    }

    public double getVolumeAsCylinder() {
        return height * (diameter / 2.0) * Math.PI;
    }

    public void setCapType(final Cap capType) {
        if (capType == null) throw new NullPointerException("capType cannot be null");
        this.capType = capType;
    }

    // potentially more methods...

}

0

IMHO thường không có đủ các lớp như thế này trong các hệ thống hướng đối tượng nặng nề. Tôi cần phải cẩn thận đủ điều kiện đó.

Tất nhiên, nếu các trường dữ liệu có phạm vi và khả năng hiển thị rộng, điều đó có thể cực kỳ không mong muốn nếu có hàng trăm hoặc hàng ngàn vị trí trong cơ sở mã của bạn giả mạo dữ liệu đó. Đó là yêu cầu rắc rối và khó khăn để duy trì bất biến. Tuy nhiên, điều đó không có nghĩa là mọi lớp đơn lẻ trong toàn bộ cơ sở mã đều có lợi từ việc che giấu thông tin.

Nhưng có nhiều trường hợp các trường dữ liệu như vậy sẽ có phạm vi rất hẹp. Một ví dụ rất đơn giản là một Nodelớp riêng của cấu trúc dữ liệu. Nó thường có thể đơn giản hóa mã rất nhiều bằng cách giảm số lượng tương tác đối tượng đang diễn ra nếu nói Nodeđơn giản có thể bao gồm dữ liệu thô. Điều đó phục vụ như một cơ chế tách rời vì phiên bản thay thế có thể yêu cầu khớp nối hai chiều từ, nói Tree->NodeNode->Treetrái ngược với đơn giản Tree->Node Data.

Một ví dụ phức tạp hơn sẽ là các hệ thống thành phần thực thể như thường được sử dụng trong các công cụ trò chơi. Trong những trường hợp đó, các thành phần thường chỉ là dữ liệu thô và các lớp giống như dữ liệu bạn đã hiển thị. Tuy nhiên, phạm vi / khả năng hiển thị của chúng có xu hướng bị giới hạn do thường chỉ có một hoặc hai hệ thống có thể truy cập loại thành phần cụ thể đó. Kết quả là bạn vẫn có xu hướng thấy khá dễ dàng để duy trì bất biến trong các hệ thống đó và hơn nữa, các hệ thống như vậy có rất ít object->objecttương tác, giúp rất dễ hiểu những gì đang diễn ra ở tầm mắt của con chim.

Trong những trường hợp như vậy, bạn có thể kết thúc với một cái gì đó giống như tương tác này (sơ đồ này biểu thị các tương tác, không phải khớp nối, vì sơ đồ khớp nối có thể bao gồm các giao diện trừu tượng cho hình ảnh thứ hai bên dưới):

nhập mô tả hình ảnh ở đây

... trái ngược với điều này:

nhập mô tả hình ảnh ở đây

... Và loại hệ thống trước đây có xu hướng dễ bảo trì hơn rất nhiều và lý do về tính chính xác mặc dù thực tế là các phụ thuộc đang thực sự chảy vào dữ liệu. Bạn nhận được ít khớp nối hơn chủ yếu vì nhiều thứ có thể được chuyển thành dữ liệu thô thay vì các đối tượng tương tác với nhau tạo thành một biểu đồ tương tác rất phức tạp.


-1

Thậm chí còn có nhiều sinh vật kỳ lạ tồn tại trong thế giới OOP. Tôi đã từng tạo một lớp, trừu tượng và không chứa gì cả, nó chỉ là một phụ huynh chung của hai lớp khác ... đó là lớp Cổng:

SceneMember 
Message extends SceneMember
Port extends SceneMember
InputPort extends Port
OutputPort extends Port

Vì vậy, SceneMember là lớp cơ sở, nó thực hiện tất cả các công việc cần phải xuất hiện trên cảnh: thêm, xóa, get-set ID, v.v. Tin nhắn là kết nối giữa các cổng, nó có cuộc sống riêng. InputPort và OutputPort chứa các chức năng cụ thể của riêng họ.

Cảng trống. Nó chỉ được sử dụng để nhóm InputPort và OutputPort với nhau, ví dụ, một danh sách cổng. Nó trống vì SceneMember chứa tất cả nội dung hoạt động như một thành viên và InputPort và OutputPort chứa các tác vụ được chỉ định cổng. InputPort và OutputPort khác nhau đến mức chúng không có chức năng chung (ngoại trừ SceneMember). Vì vậy, Cảng trống rỗng. Nhưng nó hợp pháp.

Có lẽ đó là một antipotype , nhưng tôi thích nó.

(Nó giống như từ "bạn đời", được sử dụng cho cả "vợ" và "chồng". Bạn không bao giờ sử dụng từ "bạn đời" cho một người cụ thể, bởi vì bạn biết giới tính của anh ấy / cô ấy, và nó không quan trọng nếu anh ấy / cô ấy đã kết hôn hoặc không, vì vậy bạn sử dụng "ai đó", nhưng nó vẫn tồn tại và được sử dụng trong các tình huống trừu tượng, hiếm gặp, ví dụ như một văn bản luật.)


1
Tại sao các cổng của bạn cần phải mở rộng SceneMember? Tại sao không tạo các lớp cổng để hoạt động trên SceneMembers?
Michael K

1
Vậy tại sao không sử dụng mẫu giao diện đánh dấu tiêu chuẩn? Về cơ bản giống hệt với lớp cơ sở trừu tượng trống rỗng của bạn, nhưng đó là một thành ngữ phổ biến hơn nhiều.
TMN

1
@Michael: Chỉ vì lý do lý thuyết, tôi dành riêng Cảng để sử dụng trong tương lai, nhưng tương lai này chưa đến, và có lẽ sẽ không bao giờ. Tôi đã không nhận ra rằng họ không có điểm chung nào cả, không giống như tên của họ. Tôi sẽ bồi thường cho tất cả những người phải chịu bất kỳ tổn thất nào xảy ra bởi lớp trống đó ...
ern0

1
@TMN: Các kiểu SceneMember (đạo hàm) có phương thức getMemberType (), có một số trường hợp khi Cảnh được quét để tìm tập hợp con của các đối tượng SceneMember.
ern0

4
Điều này không trả lời câu hỏi.
Eva
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.