Hai giao diện có chữ ký giống hệt nhau


13

Tôi đang cố gắng mô hình hóa một trò chơi bài trong đó thẻ có hai bộ tính năng quan trọng:

Đầu tiên là một hiệu ứng. Đây là những thay đổi về trạng thái trò chơi xảy ra khi bạn chơi bài. Giao diện cho hiệu ứng như sau:

boolean isPlayable(Player p, GameState gs);
void play(Player p, GameState gs);

Và bạn có thể coi thẻ có thể chơi được nếu và chỉ khi bạn có thể đáp ứng chi phí của nó và tất cả các hiệu ứng của nó đều có thể chơi được. Thích như vậy:

// in Card class
boolean isPlayable(Player p, GameState gs) {
    if(p.resource < this.cost) return false;
    for(Effect e : this.effects) {
        if(!e.isPlayable(p,gs)) return false;
    }
    return true;
}

Được rồi, cho đến nay, khá đơn giản.

Các tính năng khác trên thẻ là khả năng. Những khả năng này là những thay đổi về trạng thái trò chơi mà bạn có thể kích hoạt theo ý muốn. Khi đến với giao diện cho những thứ này, tôi nhận ra rằng họ cần một phương pháp để xác định xem chúng có thể được kích hoạt hay không và một phương thức để thực hiện kích hoạt. Nó kết thúc là

boolean isActivatable(Player p, GameState gs);
void activate(Player p, GameState gs);

Và tôi nhận ra rằng ngoại trừ việc gọi nó là "kích hoạt" thay vì "chơi" AbilityEffectcó cùng chữ ký.


Có phải là một điều xấu khi có nhiều giao diện với một chữ ký giống hệt nhau? Tôi có nên đơn giản sử dụng một và có hai bộ giao diện giống nhau không? Như vậy:

Set<Effect> effects;
Set<Effect> abilities;

Nếu vậy, tôi nên thực hiện các bước tái cấu trúc nào nếu chúng trở nên không giống nhau (vì nhiều tính năng được phát hành), đặc biệt nếu chúng khác nhau (nghĩa là cả hai đều đạt được thứ gì đó không nên, thay vì chỉ có một và cái kia là một tập hợp con hoàn chỉnh)? Tôi đặc biệt lo ngại rằng việc kết hợp chúng sẽ không bền vững ngay khi có gì đó thay đổi.

Bản in tốt:

Tôi nhận ra câu hỏi này được sinh ra từ phát triển trò chơi, nhưng tôi cảm thấy đó là vấn đề có thể dễ dàng phát triển trong quá trình phát triển phi trò chơi, đặc biệt là khi cố gắng điều chỉnh mô hình kinh doanh của nhiều khách hàng trong một ứng dụng chỉ xảy ra với mỗi dự án tôi từng thực hiện với nhiều hơn một ảnh hưởng kinh doanh ... Ngoài ra, đoạn mã được sử dụng là đoạn mã Java, nhưng điều này có thể dễ dàng áp dụng cho vô số ngôn ngữ hướng đối tượng.


Chỉ cần làm theo KISSYAGNI và bạn sẽ ổn thôi.
Bernard

2
Lý do duy nhất mà câu hỏi này thậm chí xuất hiện là do các chức năng của bạn có quyền truy cập vào trạng thái quá nhiều, do các tham số Player và GameState cực kỳ rộng và không bị ràng buộc.
Lars Viklund

Câu trả lời:


18

Chỉ vì hai giao diện có cùng một hợp đồng, không có nghĩa là chúng có cùng giao diện.

Nguyên tắc thay thế Liskov nêu rõ:

Đặt q (x) là một thuộc tính có thể chứng minh được về các đối tượng x thuộc loại T. Sau đó, q (y) có thể chứng minh được đối với các đối tượng y thuộc loại S trong đó S là một kiểu con của T.

Hay nói cách khác: Bất cứ điều gì đúng với giao diện hoặc siêu kiểu đều phải đúng với tất cả các kiểu con của nó.

Nếu tôi hiểu đúng mô tả của bạn, một khả năng không phải là một hiệu ứng và một hiệu ứng không phải là một khả năng. Nếu một trong hai thay đổi hợp đồng, không chắc người kia sẽ thay đổi. Tôi có thể thấy không có lý do chính đáng để cố gắng ràng buộc họ với nhau.


2

Từ Wikipedia : " giao diện thường được sử dụng để xác định loại trừu tượng không chứa dữ liệu, nhưng phơi bày các hành vi được xác định là phương thức ". Theo tôi, một giao diện được sử dụng để mô tả một hành vi, vì vậy nếu bạn có các hành vi khác nhau thì sẽ có các giao diện khác nhau. Đọc câu hỏi của bạn ấn tượng mà tôi nhận được là bạn đang nói về các hành vi khác nhau để các giao diện khác nhau có thể là cách tiếp cận tốt nhất.

Một điểm khác mà bản thân bạn nói là nếu một trong những hành vi đó thay đổi. Vậy thì điều gì sẽ xảy ra khi bạn chỉ có một giao diện?


1

Nếu các quy tắc của trò chơi bài của bạn phân biệt giữa "hiệu ứng" và "khả năng", bạn cần đảm bảo rằng chúng là các giao diện khác nhau. Điều này sẽ giữ cho bạn khỏi vô tình sử dụng một trong số họ, nơi khác là bắt buộc.

Điều đó nói rằng, nếu chúng cực kỳ giống nhau, có thể có ý nghĩa để lấy chúng từ một tổ tiên chung. Hãy xem xét một cách cẩn thận: Bạn có lý do để tin rằng "hiệu ứng" và "khả năng" sẽ luôn nhất thiết phải có giao diện giống nhau không? Nếu bạn thêm một yếu tố vào effectgiao diện, bạn có cần thêm yếu tố đó vào abilitygiao diện không?

Nếu vậy, thì bạn có thể đặt các phần tử như vậy trong một featuregiao diện chung mà cả hai đều xuất phát. Nếu không, thì bạn không nên cố gắng hợp nhất chúng - bạn sẽ lãng phí thời gian để di chuyển công cụ giữa các giao diện cơ bản và giao diện dẫn xuất. Tuy nhiên, vì bạn không có ý định thực sự sử dụng giao diện cơ bản chung cho bất cứ điều gì ngoại trừ "không lặp lại chính mình", nó có thể không tạo ra nhiều khác biệt. Và, nếu bạn tuân theo ý định đó, tôi đoán là nếu bạn chọn sai khi bắt đầu, việc tái cấu trúc để sửa nó sau này có thể tương đối đơn giản.


0

Những gì bạn đang thấy về cơ bản là một tạo tác của tính biểu cảm hạn chế của các hệ thống loại.

Về mặt lý thuyết, nếu hệ thống loại của bạn cho phép bạn chỉ định chính xác hành vi của hai giao diện đó, thì chữ ký của chúng sẽ khác nhau vì hành vi của chúng khác nhau. Trên thực tế, tính biểu cảm của các hệ thống loại bị hạn chế bởi các hạn chế cơ bản như Vấn đề dừng và Định lý của Rice, vì vậy không phải mọi khía cạnh của hành vi đều có thể được thể hiện.

Bây giờ, các hệ thống loại khác nhau có mức độ biểu cảm khác nhau, nhưng sẽ luôn có một cái gì đó không thể được thể hiện.

Ví dụ: hai giao diện có hành vi lỗi khác nhau có thể có cùng chữ ký trong C #, nhưng không có trong Java (vì trong các ngoại lệ Java là một phần của chữ ký). Hai giao diện có hành vi chỉ khác nhau về tác dụng phụ của chúng có thể có cùng chữ ký trong Java, nhưng sẽ có chữ ký khác nhau trong Haskell.

Vì vậy, luôn luôn có khả năng bạn sẽ kết thúc với cùng một chữ ký cho các hành vi khác nhau. Nếu bạn nghĩ rằng điều quan trọng là có thể phân biệt giữa hai hành vi đó không chỉ ở mức độ danh nghĩa, thì bạn cần phải chuyển sang một hệ thống loại biểu cảm hơn (hoặc khác biệt).

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.