ดิ้นรนกับหลักการความรับผิดชอบเดี่ยว


11

ลองพิจารณาตัวอย่างนี้:

ฉันมีเว็บไซต์ ช่วยให้ผู้ใช้สามารถโพสต์ (สามารถเป็นอะไรก็ได้) และเพิ่มแท็กที่อธิบายโพสต์ ในรหัสฉันมีสองคลาสที่แสดงถึงการโพสต์และแท็ก ให้เรียกชั้นเรียนเหล่านี้และPostTag

Postดูแลการสร้างโพสต์การลบโพสต์อัปเดตโพสต์ ฯลฯ Tagดูแลการสร้างแท็กการลบแท็กอัปเดตแท็ก ฯลฯ

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

ในอีกด้านหนึ่งPostคลาสอาจมีฟังก์ชันที่ใช้Tagเป็นพารามิเตอร์จากนั้นเก็บไว้ในรายการของแท็ก บนมืออื่น ๆ ที่Tagชั้นจะมีฟังก์ชั่นที่ใช้เวลาที่Postเป็นพารามิเตอร์และการเชื่อมโยงไปยังTagPost

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

บางทีการใส่ไว้ในทั้งสองคลาสเป็นคำตอบที่ถูกต้องหรือไม่

คำตอบ:


11

เช่นเดียวกับรหัสโจรสลัด SRP เป็นแนวทางมากกว่ากฎและมันก็ไม่ได้เป็นเพียงคำพูดที่ดี นักพัฒนาส่วนใหญ่ยอมรับการนิยามใหม่ของ Martin Fowler (ในRefactoring ) และ Robert Martin (ในClean Code ) แนะนำว่าชั้นควรมีเหตุผลเพียงอย่างเดียวในการเปลี่ยนแปลง (เมื่อเทียบกับความรับผิดชอบเดียว)

มันเป็นแนวทางที่ดีมั่นคง (แก้ตัวการเล่นสำนวน) แต่มันเกือบจะอันตรายพอที่จะวางสายได้เพราะมันไม่สนใจมัน

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

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

// C-style-language pseudo-code
class Post {
    string _title;
    string _content;
    Date _date;
    List<Tag> _tags;

    Post(string title, string content) {
        _title = title;
        _content = content;
        _date = Now;
        _tags = new List<Tag>();
    }

    Tag[] getTags() {
        return _tags.toArray();
    }

    void addTag(Tag tag) {
        if (_tags.contains(tag)) {
            throw "Cannot add tag twice";
        }

        _tags.Add(tag);
        tag.referencePost(this);
    }

    // more stuff here, obviously
}

class Tag {
    string _name;
    List<Post> _posts;

    Tag(string name) {
        _name = name;
    }

    Post[] getPosts() {
        return _posts.toArray();
    }

    void referencePost(Post post) {
        if (!post.getTags().contains(this) || _posts.contains(post)) {
            throw "Only reference a post by calling Post.addTag()";
        }

        _posts.Add(post);
    }

    // more stuff here too
}

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


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

@AndresF: ฉันเห็นด้วยกับคุณดังนั้นฉันจึงไม่ได้เขียนคำตอบไว้อย่างชัดเจน ฉันได้แก้ไขอย่างมีนัยสำคัญ (ขอโทษที่จะ upvoter ก่อนหน้านี้หากมีการเปลี่ยนแปลงความหมายตามที่คุณเห็นมัน.)
สาธารณรัฐประชาธิปไตยประชาชนลาว

6

ไม่ไม่ได้ทั้งคู่! มันควรจะอยู่ในที่เดียว

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

ความรับผิดชอบที่ดีPostคือ "รู้จักผู้แต่งเนื้อหาและวันที่อัพเดทล่าสุด" ความรับผิดชอบที่ดีTagคือ "รู้ชื่อและวัตถุประสงค์ (อ่าน: คำอธิบาย)" ความรับผิดชอบที่ดีStoreคือ "รู้โพสต์และแท็กทั้งหมดและสามารถเพิ่มลบและค้นหาได้"

ถ้าคุณดูผู้เข้าร่วมทั้งสามคนใครคือผู้ที่ควรมีความรู้เกี่ยวกับความสัมพันธ์ของ Post-Tag มากที่สุด?

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


หากโพสต์แต่ละรายการมีแท็กและ / หรือแต่ละแท็กมีรายการโพสต์ที่รวมไว้โพสต์หนึ่งสามารถตอบคำถามได้อย่างง่ายดาย "โพสต์ x รวมแท็ก y" มีวิธีใดที่จะตอบคำถามได้อย่างมีประสิทธิภาพโดยไม่ต้องมีความรับผิดชอบในชั้นเรียนนอกเหนือจากการใช้บางอย่างเช่นConditionalWeakTable(สมมติว่ามีโชคดีพอที่จะมีกรอบที่มีอยู่)?
supercat

3

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

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

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


2

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

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


1

โดยส่วนตัวฉันจะไม่เพิ่มฟังก์ชันการทำงานนั้นให้กับทั้งสองอย่าง

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

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

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


0

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

จากมุมมองโพสต์ ...
หากการแก้ไขหรือสร้างโพสต์กิจกรรมรองกลายเป็นการจัดการความสัมพันธ์ของแท็ก

  1. เพิ่มแท็กที่มีอยู่ลงในโพสต์
  2. ลบแท็กจากโพสต์

IMO การสร้างแท็กใหม่อย่างสมบูรณ์ไม่ได้อยู่ที่นี่

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

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

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