สองอินเตอร์เฟสที่มีลายเซ็นเหมือนกัน


13

ฉันพยายามจำลองเกมการ์ดโดยที่การ์ดมีคุณสมบัติที่สำคัญสองชุด:

ที่แรกก็คือผลกระทบ นี่คือการเปลี่ยนแปลงสถานะเกมที่เกิดขึ้นเมื่อคุณเล่นไพ่ อินเตอร์เฟสสำหรับเอฟเฟกต์มีดังนี้:

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

และคุณสามารถพิจารณาว่าการ์ดนั้นสามารถเล่นได้ถ้าหากคุณมีราคาที่เหมาะสมและเอฟเฟกต์ทั้งหมดสามารถเล่นได้ ชอบมาก

// 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;
}

โอเคจนถึงตอนนี้ค่อนข้างง่าย

ฟีเจอร์ชุดอื่น ๆ ในการ์ดคือความสามารถ ความสามารถเหล่านี้เป็นการเปลี่ยนแปลงสถานะของเกมที่คุณสามารถเปิดใช้งานได้ตามต้องการ เมื่อมากับอินเทอร์เฟซสำหรับสิ่งเหล่านี้ฉันรู้ว่าพวกเขาต้องการวิธีในการพิจารณาว่าสามารถเปิดใช้งานหรือไม่และวิธีการเปิดใช้งาน มันจบลงด้วยการเป็น

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

และฉันรู้ว่ามีข้อยกเว้นในการเรียกว่า "เปิดใช้งาน" แทน "เล่น" AbilityและEffectมีลายเซ็นเหมือนกันแน่นอน


มันเป็นสิ่งที่ดีหรือไม่ที่มีหลายอินเตอร์เฟสที่มีลายเซ็นเหมือนกัน? ฉันควรใช้เพียงหนึ่งชุดและมีอินเทอร์เฟซเดียวกันสองชุดหรือไม่ ดังนั้น:

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

ถ้าเป็นเช่นนั้นฉันควรทำตามขั้นตอนการเปลี่ยนโฉมใหม่อย่างไรหากถนนเหล่านั้นไม่เหมือนกัน (เมื่อมีการเปิดฟีเจอร์เพิ่มเติม) โดยเฉพาะอย่างยิ่งหากพวกเขาต่างกัน (เช่นพวกเขาทั้งคู่ได้รับสิ่งอื่น และอีกคนเป็นเซตย่อยที่สมบูรณ์) ฉันกังวลเป็นอย่างยิ่งว่าการรวมพวกเขาจะไม่ยั่งยืนทันทีที่มีการเปลี่ยนแปลงบางอย่าง

พิมพ์ดี:

ฉันรู้ว่าคำถามนี้เกิดจากการพัฒนาเกม แต่ฉันรู้สึกว่ามันเป็นปัญหาที่สามารถคืบคลานไปได้อย่างง่ายดายในการพัฒนาที่ไม่ใช่เกมโดยเฉพาะอย่างยิ่งเมื่อพยายามรองรับโมเดลธุรกิจของลูกค้าหลายรายในแอปพลิเคชันเดียว ทุกโครงการที่ฉันเคยทำด้วยอิทธิพลทางธุรกิจมากกว่าหนึ่ง ... นอกจากนี้ตัวอย่างที่ใช้คือตัวอย่างของ Java แต่สิ่งนี้สามารถนำไปใช้กับภาษาเชิงวัตถุจำนวนมากได้อย่างง่ายดาย


เพียงแค่ติดตามKISSและYAGNIและคุณควรจะสบายดี
เบอร์นาร์ด

2
เหตุผลเดียวที่คำถามนี้ปรากฏขึ้นก็คือเนื่องจากฟังก์ชั่นของคุณสามารถเข้าถึงสถานะได้มากเกินไปเนื่องจากพารามิเตอร์ Player และ GameState ที่กว้างและไม่น่าเชื่อ
Lars Viklund

คำตอบ:


18

เพียงเพราะสองอินเตอร์เฟสมีสัญญาเหมือนกันไม่ได้หมายความว่ามันเป็นอินเทอร์เฟซเดียวกัน

หลักการทดแทนของ Liskov :

ให้ q (x) เป็นคุณสมบัติที่พิสูจน์ได้เกี่ยวกับวัตถุ x ชนิด T จากนั้น q (y) ควรจะพิสูจน์ได้สำหรับวัตถุ y ประเภท S ที่ S เป็นชนิดย่อยของ T

หรือกล่าวอีกนัยหนึ่ง: สิ่งใดก็ตามที่เป็นจริงของอินเทอร์เฟซหรือซุปเปอร์ชนิดควรเป็นจริงของชนิดย่อยทั้งหมด

หากฉันเข้าใจคำอธิบายของคุณอย่างถูกต้องความสามารถนั้นไม่ใช่ผลกระทบและผลกระทบจะไม่เป็นความสามารถ หากฝ่ายใดฝ่ายหนึ่งเปลี่ยนสัญญาก็ไม่น่าเป็นไปได้อีกฝ่ายจะเปลี่ยนสัญญา ฉันไม่เห็นเหตุผลที่ดีที่จะพยายามผูกมัดกันและกัน


2

จากวิกิพีเดีย : " อินเทอร์เฟซมักใช้เพื่อกำหนดประเภทนามธรรมที่ไม่มีข้อมูล แต่แสดงพฤติกรรมที่กำหนดเป็นวิธีการ " ในความคิดของฉันมีการใช้อินเทอร์เฟซเพื่ออธิบายพฤติกรรมดังนั้นหากคุณมีพฤติกรรมที่แตกต่างกัน การอ่านคำถามของคุณความประทับใจที่ฉันได้รับคือคุณกำลังพูดถึงพฤติกรรมที่แตกต่างดังนั้นอินเทอร์เฟซที่แตกต่างกันอาจเป็นวิธีที่ดีที่สุด

อีกจุดหนึ่งที่คุณบอกว่าเป็นพฤติกรรมอย่างใดอย่างหนึ่ง ถ้าเช่นนั้นคุณจะมีอินเทอร์เฟซเดียวอยู่


1

หากกฎของเกมการ์ดของคุณสร้างความแตกต่างระหว่าง "เอฟเฟกต์" และ "ความสามารถ" คุณต้องตรวจสอบให้แน่ใจว่าพวกเขาเป็นอินเทอร์เฟซที่แตกต่างกัน สิ่งนี้จะป้องกันคุณจากการใช้หนึ่งในที่ที่จำเป็น

ที่กล่าวว่าหากพวกเขามีความคล้ายคลึงกันมากมันอาจทำให้รู้สึกถึงการสืบเชื้อสายมาจากบรรพบุรุษร่วมกัน พิจารณาอย่างถี่ถ้วน: คุณมีเหตุผลที่เชื่อหรือไม่ว่า "เอฟเฟ็กต์" และ "ความสามารถ" จะต้องมีอินเทอร์เฟซเดียวกันอยู่เสมอ หากคุณเพิ่มองค์ประกอบให้กับeffectอินเทอร์เฟซคุณคาดหวังว่าจะต้องมีองค์ประกอบเดียวกันนี้ในabilityอินเตอร์เฟสหรือไม่

ถ้าเป็นเช่นนั้นคุณสามารถวางองค์ประกอบดังกล่าวในfeatureอินเทอร์เฟซทั่วไปซึ่งได้รับทั้งสองอย่าง ถ้าไม่เช่นนั้นคุณไม่ควรพยายามรวมมันเข้าด้วยกัน - คุณจะเสียเวลาในการย้ายสิ่งต่าง ๆ ระหว่างส่วนต่อประสานและส่วนต่อประสานที่ได้รับมา อย่างไรก็ตามเนื่องจากคุณไม่ได้ตั้งใจจะใช้อินเทอร์เฟซพื้นฐานทั่วไปสำหรับสิ่งใดนอกจาก "ไม่ต้องทำซ้ำตัวเอง" จึงอาจไม่สร้างความแตกต่างมากนัก และถ้าคุณยึดติดกับความตั้งใจนั้นฉันเดาว่าถ้าคุณเลือกผิดตั้งแต่เริ่มต้นการเปลี่ยนการแก้ไขในภายหลังอาจจะค่อนข้างง่าย


0

สิ่งที่คุณเห็นนั้นเป็นสิ่งประดิษฐ์ของประเภทระบบที่ จำกัด

ในทางทฤษฎีหากระบบประเภทของคุณอนุญาตให้คุณระบุพฤติกรรมของอินเทอร์เฟซทั้งสองอย่างถูกต้องแล้วลายเซ็นของพวกเขาจะแตกต่างกันเนื่องจากพฤติกรรมของพวกเขาแตกต่างกัน ในทางปฏิบัติความหมายของประเภทระบบที่ถูก จำกัด ด้วยข้อ จำกัด พื้นฐานเช่นปัญหาการหยุดชะงักและทฤษฎีของข้าวดังนั้นทุกพฤติกรรมสามารถแสดงได้

ตอนนี้ระบบที่แตกต่างกันมีระดับความหมายที่ต่างกัน แต่จะมีบางสิ่งที่ไม่สามารถแสดงออกได้เสมอ

ตัวอย่างเช่น: สองอินเตอร์เฟสที่มีพฤติกรรมผิดพลาดต่างกันอาจมีลายเซ็นเหมือนกันใน C # แต่ไม่ใช่ใน Java (เพราะในข้อยกเว้น Java เป็นส่วนหนึ่งของลายเซ็น) สองอินเตอร์เฟสที่มีพฤติกรรมแตกต่างกันในผลข้างเคียงของพวกเขาอาจมีลายเซ็นเดียวกันใน Java แต่จะมีลายเซ็นที่แตกต่างกันใน Haskell

ดังนั้นจึงเป็นไปได้เสมอที่คุณจะพบกับลายเซ็นเดียวกันสำหรับพฤติกรรมที่แตกต่างกัน หากคุณคิดว่ามันเป็นสิ่งสำคัญที่จะสามารถแยกแยะความแตกต่างระหว่างพฤติกรรมทั้งสองนี้ได้มากกว่าแค่ระดับเล็กน้อยคุณต้องเปลี่ยนไปใช้ระบบประเภทที่แสดงออกมากขึ้น (หรือแตกต่างกัน)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.