การละเมิด LSP เคยถูกหรือไม่?


10

ฉันกำลังติดตามคำถามนี้แต่ฉันเปลี่ยนโฟกัสจากโค้ดเป็นหลักการ

จากความเข้าใจของฉันเกี่ยวกับหลักการทดแทน Liskov (LSP) ไม่ว่าวิธีการใดที่อยู่ในคลาสพื้นฐานของฉันพวกเขาจะต้องดำเนินการในคลาสย่อยของฉันและตามหน้านี้หากคุณแทนที่วิธีในคลาสพื้นฐานและไม่ทำอะไรเลย คุณกำลังละเมิดหลักการ

ตอนนี้ปัญหาของฉันสามารถสรุปได้เช่นนี้ฉันมีนามธรรมWeapon classและสองชั้นและSword ReloadableหากReloadableมีข้อมูลเฉพาะที่methodเรียกว่าReload()ฉันจะต้องลดความเร็วเพื่อเข้าถึงmethodและถ้าคุณต้องการหลีกเลี่ยงปัญหานั้น

Strategy Patternจากนั้นผมก็คิดของการใช้ วิธีนี้แต่ละอาวุธเป็นเพียงตระหนักถึงการกระทำที่มีความสามารถในการดำเนินการดังนั้นสำหรับตัวอย่างเช่นReloadableอาวุธอย่างเห็นได้ชัดสามารถโหลด แต่ไม่สามารถและไม่ได้ตระหนักถึงSword Reload class/methodตามที่ระบุไว้ในโพสต์ Stack Overflow ของฉันฉันไม่จำเป็นต้องลดความเร็วและฉันสามารถเก็บList<Weapon>สะสม

ในฟอรัมอื่นคำตอบแรกที่แนะนำเพื่อให้SwordระวังReloadเพียงไม่ทำอะไรเลย ได้รับคำตอบเดียวกันนี้ในหน้า Stack Overflow ที่ฉันลิงค์ไปด้านบน

ฉันไม่เข้าใจว่าทำไม ทำไมการละเมิดหลักการและอนุญาตให้ Sword ต้องระวังReloadและปล่อยให้มันว่างเปล่า อย่างที่ฉันบอกไว้ในโพสต์ Stack Overflow SP จะแก้ปัญหาของฉันได้ค่อนข้างมาก

ทำไมมันไม่เป็นทางออกที่ทำงานได้?

public final Weapon{

    private final String name;
    private final int damage;
    private final List<AttackStrategy> validactions;
    private final List<Actions> standardActions;

    private Weapon(String name, int damage, List<AttackStrategy> standardActions, List<Actions> attacks)
    {
        this.name = name;
        this.damage = damage;
        standardActions = new ArrayList<Actions>(standardActions);
        validAttacks = new ArrayList<AttackStrategy>(validActions);
    }

    public void standardAction(String action){} // -- Can call reload or aim here.  

    public int attack(String action){} // - Call any actions that are attacks. 

    public static Weapon Sword(String name, damage, List<AttackStrategy> standardActions, List<Actions> attacks){
        return new Weapon(name, damage,standardActions, attacks) ;
    }

}

อินเตอร์เฟซการโจมตีและการใช้งาน:

public interface AttackStrategy{
    void attack(Enemy enemy);
}

public class Shoot implements AttackStrategy {
    public void attack(Enemy enemy){
        //code to shoot
    }
}

public class Strike implements AttackStrategy {
    public void attack(Enemy enemy){
        //code to strike
    }
}

2
class Weapon { bool supportsReload(); void reload(); }คุณสามารถทำได้ ลูกค้าจะทดสอบว่ารองรับก่อนโหลดซ้ำหรือไม่ reloadจะถูกกำหนดตามสัญญาที่จะโยน !supportsReload()IFF ที่เป็นไปตาม LSP iff ขับเคลื่อนคลาสที่เป็นไปตามโปรโตคอลที่ฉันเพิ่งอธิบาย
usr

3
ไม่ว่าคุณจะปล่อยreload()ว่างไว้หรือstandardActionsไม่ประกอบด้วยการบรรจุซ้ำเป็นเพียงกลไกที่แตกต่างกัน ไม่มีความแตกต่างพื้นฐาน คุณสามารถทำได้ทั้งสองอย่าง => ทางออกของคุณเป็นไปได้ (ซึ่งเป็นคำถามของคุณ); Sword ไม่จำเป็นต้องรู้เรื่องการรีโหลดถ้า Weapon นั้นมีการใช้งานเป็นค่าว่างเปล่า
usr

27
ฉันเขียนบทความชุดหนึ่งเพื่อสำรวจปัญหาที่หลากหลายด้วยเทคนิคที่หลากหลายสำหรับการแก้ปัญหานี้ สรุป: ไม่พยายามที่จะจับกฎของเกมของคุณในระบบการพิมพ์ของภาษา จับกฎของเกมในวัตถุซึ่งเป็นตัวแทนและการบังคับใช้กฎระเบียบในระดับของเกมตรรกะที่ไม่ได้อยู่ในระดับของระบบการพิมพ์ที่ ไม่มีเหตุผลที่จะเชื่อว่าระบบประเภทใดก็ตามที่คุณใช้นั้นมีความซับซ้อนเพียงพอที่จะเป็นตัวแทนของเกมตรรกะของคุณ ericlippert.com/2015/04/27/wizards-and-warriors-part-one
Eric Lippert

2
@EricLippert - ขอบคุณสำหรับลิงค์ของคุณ ฉันเคยเจอบล็อกนี้มาหลายครั้งแล้ว แต่มีบางประเด็นที่ทำให้ฉันไม่ค่อยเข้าใจ แต่มันไม่ใช่ความผิดของคุณ ฉันเรียนรู้เกี่ยวกับ OOP ด้วยตัวเองและเจอผู้บริหารที่เป็นของแข็ง ครั้งแรกที่ฉันเข้ามาในบล็อกของคุณฉันไม่เข้าใจเลย แต่ฉันได้เรียนรู้เพิ่มเติมเล็กน้อยและอ่านบล็อกของคุณอีกครั้งและค่อยๆเริ่มเข้าใจบางส่วนของสิ่งที่ถูกพูด อยู่มาวันหนึ่งฉันจะเข้าใจทุกอย่างในซีรีส์นั้น ฉันหวังว่า: D

6
@SR "หากไม่ทำอะไรเลยหรือมีข้อผิดพลาดเกิดขึ้นคุณกำลังละเมิด" - ฉันคิดว่าคุณอ่านข้อความผิดจากบทความนั้น ปัญหาไม่ได้โดยตรงที่ setAltitude ไม่ได้ทำอะไรเลยมันเป็นความล้มเหลวที่จะตอบสนอง postcondition "นกจะถูกวาดที่ระดับความสูงที่กำหนด" หากคุณกำหนด postcondition ของ "reload" เป็น "ถ้ามีกระสุนเพียงพอก็สามารถใช้อาวุธโจมตีได้อีก" จากนั้นก็ไม่ทำอะไรเลยเป็นการใช้งานที่สมบูรณ์แบบสำหรับอาวุธที่ไม่ได้ใช้กระสุน
เซบาสเตียนเรดล

คำตอบ:


16

LSP มีความกังวลเกี่ยวกับชนิดย่อยและความหลากหลาย ไม่ใช่รหัสทั้งหมดที่ใช้คุณสมบัติเหล่านี้ซึ่งในกรณีนี้ LSP ไม่เกี่ยวข้อง สองกรณีการใช้งานทั่วไปของโครงสร้างภาษาที่สืบทอดซึ่งไม่ใช่กรณีของการพิมพ์ย่อยคือ:

  • การสืบทอดที่ใช้ในการสืบทอดการใช้งานของคลาสพื้นฐาน แต่ไม่ใช่ส่วนต่อประสาน ในเกือบทุกกรณีควรมีการจัดองค์ประกอบ ภาษาเช่น Java ไม่สามารถแยกการสืบทอดการใช้งานและส่วนต่อประสานได้ แต่เช่น C ++ มีการprivateสืบทอด

  • มรดกที่ใช้ในการสร้างแบบจำลองประเภทรวม / สหภาพเช่นกBaseเป็นอย่างใดอย่างหนึ่งหรือCaseA CaseBประเภทฐานไม่ได้ประกาศอินเตอร์เฟซที่เกี่ยวข้องใด ๆ ในการใช้อินสแตนซ์ของมันคุณจะต้องแปลงมันเป็นรูปธรรมที่ถูกต้อง การหล่อสามารถทำได้อย่างปลอดภัยและไม่เป็นปัญหา น่าเสียดายที่ภาษา OOP หลายภาษาไม่สามารถ จำกัด ประเภทย่อยของคลาสพื้นฐานให้เป็นชนิดย่อยที่ต้องการได้ หากรหัสภายนอกสามารถสร้างได้CaseCดังนั้นรหัสที่สมมติว่า a Baseสามารถเป็นได้CaseAหรือCaseBไม่ถูกต้องเท่านั้น สกาล่าสามารถทำสิ่งนี้ได้อย่างปลอดภัยด้วยcase classแนวคิด ใน Java สิ่งนี้สามารถสร้างแบบจำลองเมื่อBaseเป็นคลาสนามธรรมที่มีคอนสตรัคเตอร์ส่วนตัวและคลาสสแตติกที่ซ้อนกันนั้นสืบทอดมาจากฐาน

แนวคิดบางอย่างเช่นลำดับชั้นแนวคิดของวัตถุในโลกแห่งความเป็นจริงทำแผนที่ไม่ดีอย่างมากในแบบจำลองเชิงวัตถุ ความคิดเช่น“ ปืนเป็นอาวุธและดาบเป็นอาวุธดังนั้นฉันจะมีWeaponชั้นฐานที่ซึ่งGunและSwordสืบทอด” กำลังทำให้เข้าใจผิด: คำที่แท้จริงคือ - ความสัมพันธ์ไม่ได้หมายความถึงความสัมพันธ์ในแบบจำลองของเรา ปัญหาที่เกี่ยวข้องคือวัตถุอาจเป็นของหลายลำดับชั้นแนวคิดหรืออาจเปลี่ยนความสัมพันธ์ลำดับชั้นของพวกเขาในช่วงเวลาทำงานซึ่งภาษาส่วนใหญ่ไม่สามารถสร้างแบบจำลองได้เนื่องจากการสืบทอดมักจะเป็นต่อชั้นไม่ต่อวัตถุและกำหนดเวลาออกแบบไม่ทำงาน

เมื่อออกแบบแบบจำลอง OOP เราไม่ควรคำนึงถึงลำดับชั้นหรือวิธีที่คลาสหนึ่ง“ ขยาย” อีกชั้นหนึ่ง คลาสพื้นฐานไม่ใช่ที่สำหรับแยกส่วนทั่วไปของหลายคลาส ลองคิดดูว่าจะใช้วัตถุของคุณอย่างไรเช่นพฤติกรรมประเภทใดที่ผู้ใช้ของวัตถุเหล่านี้ต้องการ

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

ไม่จำเป็นต้องสร้างลำดับชั้น ทั้งสองประเภทGunและSwordอาจไม่เกี่ยวข้องทั้งหมด ในขณะที่Gunสามารถfire()และอาจจะเป็นเพียง หากคุณต้องการจัดการวัตถุเหล่านี้หลายรูปแบบคุณสามารถใช้รูปแบบอะแดปเตอร์เพื่อจับภาพด้านที่เกี่ยวข้อง ใน Java 8 สามารถทำได้ค่อนข้างสะดวกด้วยส่วนต่อประสานการทำงานและการอ้างอิง lambdas / method เช่นคุณอาจมีกลยุทธ์ที่คุณจัดหาหรือreload()Swordstrike()AttackmyGun::fire() -> mySword.strike()

ในที่สุดบางครั้งมันก็สมเหตุสมผลที่จะหลีกเลี่ยงคลาสย่อยใด ๆ เลย แต่ทำโมเดลวัตถุทั้งหมดผ่านประเภทเดียว สิ่งนี้มีความเกี่ยวข้องเป็นพิเศษในเกมเพราะวัตถุเกมจำนวนมากไม่เข้ากับลำดับชั้นใด ๆ และอาจมีความสามารถที่แตกต่างกันมาก เช่นเกมเล่นตามบทบาทอาจมีไอเท็มที่เป็นทั้งรายการเควส, บัฟสถานะของคุณด้วย +2 พละเมื่อติดตั้งมีโอกาส 20% ที่จะไม่สนใจความเสียหายที่ได้รับและมีการโจมตีระยะประชิด หรืออาจเป็นดาบที่ใส่ได้ใหม่เพราะมันคือ * เวท * ใครจะรู้ว่าเรื่องราวต้องการอะไร

แทนที่จะพยายามหาลำดับชั้นของคลาสสำหรับระเบียบนั้นดีกว่าที่จะมีคลาสที่จัดให้มีสล็อตสำหรับความสามารถต่างๆ ช่องเหล่านี้สามารถเปลี่ยนแปลงได้ที่รันไทม์ แต่ละช่องจะเป็นกลยุทธ์ / โทรกลับเหมือนหรือOnDamageReceived Attackด้วยอาวุธของเราอาจจะมีMeleeAttack, RangedAttackและReloadสล็อต ช่องเหล่านี้อาจว่างเปล่าซึ่งในกรณีนี้วัตถุไม่ได้ให้ความสามารถนี้ สล็อตจะถูกเรียกตามเงื่อนไข: if (item.attack != null) item.attack.perform().


จัดเรียงของชอบ SP ในทาง เหตุใดสล็อตจึงต้องว่างเปล่า หากพจนานุกรมไม่มีการดำเนินการให้ทำอะไรเลย

@SR ไม่ว่าช่องจะว่างเปล่าหรือไม่มีอยู่ก็ไม่สำคัญและขึ้นอยู่กับกลไกที่ใช้ในการติดตั้งช่องเหล่านี้ ฉันเขียนคำตอบนี้ด้วยสมมติฐานของภาษาที่ค่อนข้างคงที่ซึ่งสล็อตเป็นเขตข้อมูลอินสแตนซ์และมีอยู่เสมอ (เช่นการออกแบบคลาสปกติใน Java) หากเลือกโมเดลที่มีพลวัตมากขึ้นซึ่งช่องเป็นรายการในพจนานุกรม (เช่นการใช้ HashMap ใน Java หรือวัตถุ Python ปกติ) ช่องนั้นไม่จำเป็นต้องมีอยู่ โปรดทราบว่าวิธีการที่มีพลวัตมากขึ้นนั้นทำให้เกิดความปลอดภัยประเภทมาก
amon

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

2
@SR ใช่รูปแบบกลยุทธ์ในบางรูปแบบน่าจะเป็นแนวทางที่สมเหตุสมผล เปรียบเทียบยังเป็นรูปแบบที่เกี่ยวข้องกับชนิดของวัตถุ: gameprogrammingpatterns.com/type-object.html
อมร

3

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

จากทั้งหมดที่กล่าวมาฉันไม่เห็นด้วยกับคำตอบของคำถามอื่นของคุณเป็นพิเศษ การswordได้รับมรดกweaponเป็นสิ่งที่น่ากลัวและไร้เดียงสา OO ซึ่งจะนำไปสู่วิธีการที่ไม่มีการตรวจสอบหรือการตรวจสอบประเภทที่เกี่ยวกับรหัส

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


ฉันคิดว่ามันสมบูรณ์แบบ ฉันสามารถใช้ SP ได้ แต่พวกเขาไม่ชอบการค้าเพียงแค่ต้องระวังพวกเขา ดูการแก้ไขของฉันสำหรับสิ่งที่ฉันมีอยู่ในใจ

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

Fwiw in Destiny 2 ดาบใช้กระสุนด้วยเหตุผลบางอย่าง!

@ CAD97 - นี่เป็นประเภทของความคิดที่ฉันเคยเห็นเกี่ยวกับปัญหานี้ มีดาบที่มีกระสุนไม่ จำกัด จึงไม่โหลดซ้ำ นี่เป็นเพียงการผลักดันปัญหารอบ ๆ หรือซ่อนมัน ถ้าฉันแนะนำลูกระเบิดมือแล้วจะเป็นอย่างไร? ระเบิดไม่มีกระสุนหรือยิงและไม่ควรตระหนักถึงวิธีการดังกล่าว

1
ฉันใช้ CAD97 กับสิ่งนี้ และจะสร้างสิ่งWeaponBuilderที่สามารถสร้างดาบและปืนด้วยการเขียนอาวุธของกลยุทธ์
Chris Wohlert

3

แน่นอนมันเป็นทางออกที่ทำงานได้; มันเป็นความคิดที่แย่มาก

ปัญหาไม่ได้เกิดขึ้นถ้าคุณมีอินสแตนซ์เดียวนี้ที่คุณใส่รีโหลดบนคลาสพื้นฐานของคุณ ปัญหาคือคุณต้องใส่ "การแกว่ง", "ยิง", "ปัดป้อง", "เคาะ", "ขัดเงา", "ถอดแยกชิ้นส่วน", "คมชัด" และ "แทนที่ตอกตะปูที่ปลายแหลมของสโมสร" วิธีการในชั้นฐานของคุณ

ประเด็นของ LSP คืออัลกอริธึมระดับสูงของคุณจำเป็นต้องทำงานและมีเหตุผล ดังนั้นถ้าฉันมีรหัสเช่นนี้:

if (isEquipped(weapon)) {
   reload();
}

ทีนี้ถ้ามันมีข้อยกเว้นที่ไม่ได้นำมาใช้และทำให้โปรแกรมของคุณพังนั่นเป็นความคิดที่แย่มาก

หากรหัสของคุณมีลักษณะเช่นนี้

if (canReload(weapon)) {
   reload();
}
else if (canSharpen(weapon)) {
  sharpen();
}
else if (canPollish(weapon)) {
  polish();
}

จากนั้นโค้ดของคุณอาจกลายเป็นรกไปด้วยคุณสมบัติที่เฉพาะเจาะจงมากซึ่งไม่เกี่ยวข้องกับแนวคิด 'อาวุธ' ที่เป็นนามธรรม

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

อัปเดต: ลองนึกถึงตัวพิมพ์ / คำศัพท์ที่เป็นนามธรรม ตัวอย่างเช่นบางทีอาวุธทุกอย่างอาจมีการ "เตรียม" ซึ่งเป็นการบรรจุกระสุนสำหรับปืนและ unsheath สำหรับดาบ


สมมติว่าฉันมีพจนานุกรมอาวุธภายในที่เก็บการกระทำสำหรับอาวุธและเมื่อผู้ใช้ผ่าน "โหลด" มันจะตรวจสอบพจนานุกรมอดีตอาวุธแอคชั่นประกอบกัปตัน (การกระทำ) ถ้าเป็นเช่นนั้นคว้าวัตถุที่เกี่ยวข้องและทำ มัน. แทนที่จะเป็นคลาสอาวุธที่มีหลายอย่างถ้า statement

ดูการแก้ไขด้านบน นี่คือสิ่งที่ฉันทราบเมื่อใช้ SP

0

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

ตอนนี้ไม่ว่าจะเป็นความคิดที่ดีหรือไม่เป็นที่ถกเถียงกันมาก แต่ถ้าคุณไม่เคยแทนที่ subclass สำหรับ baseclass แล้วความจริงที่ว่ามันไม่ทำงานไม่มีปัญหา คุณอาจมีปัญหา แต่ LSP ไม่ใช่ปัญหาในกรณีนี้


0

LSP นั้นดีเพราะอนุญาตให้ใช้รหัสการโทรไม่ต้องกังวลว่าคลาสจะทำงานอย่างไร

เช่น. ฉันสามารถเรียก Weapon.Attack () บนอาวุธทั้งหมดที่ติดตั้งบน BattleMech ของฉันและไม่ต้องกังวลว่าบางคนอาจมีข้อยกเว้นและทำให้เกมของฉันพัง

ในกรณีของคุณคุณต้องการขยายประเภทฐานของคุณด้วยฟังก์ชั่นใหม่ Attack () ไม่ใช่ปัญหาเพราะคลาส Gun สามารถติดตามกระสุนและหยุดยิงเมื่อมันหมด แต่ Reload () เป็นสิ่งใหม่และไม่ใช่ส่วนหนึ่งของการเป็นอาวุธ

ทางออกที่ง่ายคือการลดระดับฉันไม่คิดว่าคุณต้องกังวลเกี่ยวกับประสิทธิภาพมากเกินไปคุณจะไม่ทำมันทุกเฟรม

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

ถ้าอย่างนั้นคุณจะไม่ขยายชั้นเรียนให้กับปืนอีกต่อไปหรือละเมิด LSP

แต่มันก็เป็นปัญหาในระยะยาวเพราะคุณจะต้องคิดถึงกรณีพิเศษมากขึ้น Gun.SafteyOn (), Sword.WipeOffBlood () ฯลฯ และถ้าคุณใส่พวกมันทั้งหมดใน Weapon คุณจะมีคลาสพื้นฐานที่ซับซ้อนสุด ๆ ที่คุณเก็บไว้ ต้องเปลี่ยน

แก้ไข: ทำไมรูปแบบกลยุทธ์ไม่ดี (tm)

ไม่ใช่ แต่พิจารณาการตั้งค่าประสิทธิภาพและรหัสโดยรวม

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

เมื่อฉันเรียกเมธอดฉันต้องวนซ้ำรายการการกระทำนั้นและทำการจับคู่สตริงเพื่อดูว่าจะเรียก

เมื่อฉันรวบรวมรหัสและโทร Weapon.Do ("atack") แทน "Attack" ฉันจะไม่ได้รับข้อผิดพลาดในการรวบรวม

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


ผมคิดว่า SP สามารถจัดการกับทุกสิ่งที่ (ดูแก้ไขข้างต้น) ปืนจะมีSafteyOn()และจะมีSword wipeOffBlood()อาวุธแต่ละชนิดไม่ทราบวิธีอื่น ๆ (และไม่ควรเป็น)

SP นั้นใช้ได้ แต่ก็เทียบเท่ากับการดาวน์สตรีมโดยไม่มีความปลอดภัยของประเภท ฉันเดาว่าฉันกำลังตอบคำถามที่แตกต่างกันให้ฉันอัปเดต
Ewan

2
รูปแบบกลยุทธ์นั้นไม่ได้หมายถึงการค้นหาแบบไดนามิกของกลยุทธ์ในรายการหรือพจนานุกรม ทั้งสองweapon.do("attack")และประเภทที่ปลอดภัยweapon.attack.perform()อาจเป็นตัวอย่างของรูปแบบกลยุทธ์ การค้นหากลยุทธ์ด้วยชื่อมีความจำเป็นเฉพาะเมื่อกำหนดค่าวัตถุจากไฟล์ปรับแต่งแม้ว่าการใช้การสะท้อนภาพจะปลอดภัยเท่ากัน
amon

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