การเขียนโปรแกรมเชิงวัตถุ: getters / setters หรือชื่อตรรกะ


12

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

ฉันมีชั้นเรียนCharacterStylesที่มีตัวแปรสมาชิกbold, italic, underline(และอื่น ๆ บางอย่าง แต่ฉันจะปล่อยให้พวกเขาออกไปให้มันง่าย) วิธีที่ง่ายที่สุดที่จะช่วยให้ส่วนอื่น ๆ ของโปรแกรมที่จะเข้าถึงตัวแปรเหล่านี้จะเขียนวิธีการ getter / หมาเพื่อให้คุณสามารถทำและstyles.setBold(true)styles.setItalic(false)

แต่ฉันไม่ชอบสิ่งนี้ ไม่เพียงเพราะผู้คนจำนวนมากพูดว่าผู้ได้รับ / setters ทำลายการห่อหุ้ม (มันเลวร้ายจริงๆเหรอ?) แต่ส่วนใหญ่เป็นเพราะมันไม่สมเหตุสมผล ฉันคาดหวังที่จะจัดสไตล์ตัวละครผ่านวิธีการหนึ่งstyles.format("bold", true)หรือบางอย่างเช่นนั้น แต่ไม่ผ่านวิธีเหล่านี้ทั้งหมด

แม้ว่าจะมีปัญหาหนึ่งข้อ เนื่องจากคุณไม่สามารถเข้าถึงตัวแปรสมาชิกวัตถุโดยเนื้อหาของสตริงใน C ++ ฉันจะต้องเขียนคอนเทนเนอร์ if-statement / switch ขนาดใหญ่สำหรับสไตล์ทั้งหมดหรือฉันจะต้องเก็บสไตล์ไว้ในอาเรย์แบบเชื่อมโยง ( แผนที่).

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


คลาส CharacterStyles ทำสิ่งอื่นนอกเหนือจากบันเดิลสามบูลีนหรือไม่ มันบริโภคอย่างไร?
Mark Canlas

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

คุณสามารถใช้ enum เพื่อกำหนดตัวเลือกสไตล์ที่หลากหลายจากนั้นใช้คำสั่ง switch แต่คุณจัดการไม่ได้กำหนดอย่างไร
Tyanna

@Tyanna: จริง ๆ แล้วฉันก็คิดเกี่ยวกับการใช้ enum แต่นั่นเป็นเพียงรายละเอียดเล็กน้อย ฉันวางแผนที่จะตั้งค่าที่ไม่ได้กำหนดเป็น NULL นั่นไม่ใช่วิธีที่ดีที่สุดใช่ไหม
กบ

คำตอบ:


6

ใช่ getters / setters แบ่งการห่อหุ้ม - โดยทั่วไปแล้วมันเป็นเพียงเลเยอร์พิเศษระหว่างการเข้าถึงฟิลด์ต้นแบบโดยตรง คุณอาจเข้าถึงได้โดยตรง

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

DrDobbs มีบทความที่กล่าวเพิ่มเติม

สำหรับปัญหาของคุณฉันมี 2 วิธีคือ setStyle และ clearStyle (หรืออะไรก็ตาม) ที่ใช้ enum ของสไตล์ที่เป็นไปได้ คำสั่ง switch ภายในเมธอดเหล่านี้จะใช้ค่าที่เกี่ยวข้องกับตัวแปรคลาสที่เหมาะสม ด้วยวิธีนี้คุณสามารถเปลี่ยนการเป็นตัวแทนภายในของสไตล์เป็นอย่างอื่นถ้าคุณตัดสินใจที่จะเก็บไว้เป็นสตริง (สำหรับใช้ใน HTML เป็นต้น) - สิ่งที่ต้องการให้ผู้ใช้ทุกคนในชั้นเรียนของคุณเปลี่ยนด้วยหากคุณใช้ รับ / ตั้งค่าคุณสมบัติ

คุณยังคงสามารถเปิดใช้งานสตริงได้หากคุณต้องการรับค่าตามอำเภอใจมีทั้งคำสั่ง if-then ขนาดใหญ่ (ถ้ามีจำนวนน้อย) หรือแผนที่ของค่าสตริงเป็นตัวชี้วิธีโดยใช้std :: mem_fun (หรือstd :: ฟังก์ชั่น ) ดังนั้น "ตัวหนา" จะถูกเก็บไว้ในแผนที่ที่สำคัญที่มีค่าเป็น sts :: mem_fun เป็นวิธีการที่ตั้งค่าตัวแปรตัวหนาเป็นจริง (ถ้าสตริงเหมือนกันกับชื่อตัวแปรสมาชิกคุณสามารถใช้แมโคร stringifyingเพื่อลดปริมาณของรหัสที่คุณจำเป็นต้องเขียน)


คำตอบที่ยอดเยี่ยม! โดยเฉพาะอย่างยิ่งส่วนที่เกี่ยวกับการจัดเก็บข้อมูลในรูปแบบ HTML ทำให้ฉันเป็นเหตุผลที่ดีที่จะต้องไปตามถนนสายนี้ ดังนั้นคุณควรแนะนำให้เก็บสไตล์ที่แตกต่างใน enum แล้วตั้งค่าลักษณะเป็นstyles.setStyle(BOLD, true)อย่างไร ถูกต้องหรือไม่
กบ

ใช่มีเพียงฉันเท่านั้นที่มี 2 วิธีคือ setStyle (BOLD) และ clearstyle (BOLD) ลืมพารามิเตอร์ตัวที่ 2 ฉันแค่ชอบแบบนี้แล้วคุณก็สามารถโอเวอร์โหลด clearStyle เพื่อไม่ใช้พารามิเตอร์เพื่อเคลียร์แฟล็กสไตล์ทั้งหมด
gbjbaanb

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

ฉันได้รับการพยายามที่จะดำเนินการนี้ แต่มีปัญหาหนึ่งที่ผมไม่ได้พิจารณาวิธีการที่คุณใช้styles.getStyle(BOLD)เมื่อคุณไม่เพียง แต่มีตัวแปรสมาชิกประเภทบูล แต่ยังชนิดจำนวนเต็มและสตริง (ตัวอย่างเช่น: styles.getStyle(FONTSIZE)) เนื่องจากคุณไม่สามารถโอเวอร์โหลดประเภทที่คืนกลับมามากเกินไปคุณจะตั้งโปรแกรมนี้ได้อย่างไร ฉันรู้ว่าคุณสามารถใช้โมฆะพอยน์เตอร์ได้ แต่มันฟังดูแย่สำหรับฉัน คุณมีคำแนะนำในการทำเช่นนี้หรือไม่?
กบ

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

11

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

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

สำหรับตัวอย่าง pseudocode:

class TextWriter : TextDrawingInterface {
    public:
        void WriteString(string x) {
            // write some text somewhere somehow
        }
}

class BoldDecorator : TextDrawingInterface {
    public:
        void WriteString(string x) {
            // bold application on
            m_textWriter.WriteString(x);
            // bold application off
        }

        ctor (TextDrawingInterface textWriter) {
            m_textWriter = textWriter;
        }

    private:
        TextWriter m_TextWriter;
}

และอื่น ๆ สำหรับสไตล์การตกแต่งแต่ละแบบ ในการใช้งานที่ง่ายที่สุดคุณสามารถพูดได้

TextDrawingInterface GetDecoratedTextWriter() {
    return new BoldDecorator(new ItalicDecorator(new TextWriter()));
}

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


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

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

ในขณะที่นี่เป็นคำตอบที่ดีมันไม่ได้แนะนำคำถามของ op อีกครั้งหรือไม่ "ใช้ตัวหนากับ" -> จะทำยังไงดี? ใช้ setters / getters เช่น SetBold () หรือไม่ ซึ่งเป็นคำถามของ op
stijn

1
@stijn: ไม่จริง มีหลายวิธีในการหลีกเลี่ยงสถานการณ์นั้น ตัวอย่างเช่นคุณสามารถล้อมในตัวสร้างด้วยเมธอด toggleStyle (อาร์กิวเมนต์ enum) ซึ่งเพิ่มและลบตัวตกแต่งจากอาร์เรย์เพียงตกแต่งไอเท็มสุดท้ายเมื่อคุณเรียก BuildDecoratedTextWriter หรือคุณสามารถทำตามที่ rwong แนะนำและทำให้คลาสฐานซับซ้อนขึ้น ขึ้นอยู่กับสถานการณ์และ OP ไม่เจาะจงเพียงพอเกี่ยวกับข้อมูลจำเพาะโดยรวมที่จะเดาว่าอะไรดีที่สุดสำหรับเขา ดูเหมือนว่าเขาจะฉลาดพอที่จะสามารถเข้าใจได้เมื่อเขาได้รับแบบแผน
pdr

1
ฉันคิดเสมอว่ารูปแบบมัณฑนากรหมายถึงการสั่งซื้อเครื่องประดับ พิจารณาตัวอย่างรหัสที่แสดง; เราจะลบ ItalicDecorator อย่างไร? ถึงกระนั้นฉันคิดว่าสิ่งที่ชอบมัณฑนากรเป็นวิธีที่จะไป ตัวหนาตัวเอียงและขีดเส้นใต้ไม่ใช่เพียงสามสไตล์เท่านั้น มีบางกึ่ง, ย่อ, ดำ, กว้าง, ตัวเอียงพร้อมกับซัด, แคปขนาดเล็ก ฯลฯ คุณอาจต้องการวิธีในการใช้สไตล์ชุดใหญ่โดยพลการกับตัวละคร
Barry Brown

0

ฉันเรียนวิธีแก้ปัญหาที่สอง มันดูหรูหราและยืดหยุ่นมากขึ้น แม้ว่าจะเป็นการยากที่จะจินตนาการถึงประเภทอื่น ๆ ที่ไม่ใช่ตัวหนาตัวเอียงและขีดเส้นใต้ (overline?) แต่ก็เป็นการยากที่จะเพิ่มประเภทใหม่โดยใช้ตัวแปรสมาชิก

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


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

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

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

หากคุณไม่ประสบปัญหาจำนวนคุณลักษณะแบบไดนามิกคุณไม่จำเป็นต้องมีพื้นที่ยืดหยุ่นในการจัดเก็บ เป็นเรื่องจริง :) ฉันไม่เห็นด้วยกับส่วนอื่น ๆ แอตทริบิวต์ Stroring ในดิกชันนารี / hashmap / etc นั้นไม่ใช่ความคิดของฉัน
Andrzej Bobak

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