การลดสำเร็จรูปในชั้นเรียนที่ใช้ส่วนต่อประสานผ่านองค์ประกอบ


11

ฉันได้เรียน: Aว่าเป็นคอมโพสิตของจำนวนของชั้นเรียนขนาดเล็กB, และCD

B, CและDใช้อินเตอร์เฟซIB, ICและIDตามลำดับ

ตั้งแต่AรองรับทุกการทำงานของB, CและD, AการดำเนินการIB, ICและIDเช่นกัน แต่นี้โชคไม่ดีที่นำไปสู่การเป็นจำนวนมากเส้นทางใหม่ในการดำเนินการA

ชอบมาก

interface IB
{
    int Foo {get;}
}

public class B : IB
{
    public int Foo {get {return 5;}}
}

interface IC
{
    void Bar();
}

public class C : IC
{
    public void Bar()
    {
    }
}

interface ID
{
    string Bash{get; set;}
}

public class D: ID
{
    public string Bash {get;set;}
}

class A : IB, IC, ID
{
    private B b = new B();
    private C c = new C();
    private D d = new D();

    public int Foo {get {return b.Foo}}

    public A(string bash)
    {
        Bash = bash;
    }

    public void Bar()
    {
        c.Bar();
    }

    public string Bash
    {
         get {return d.Bash;}
         set {d.Bash = value;}
    }
}

มีวิธีกำจัดการเปลี่ยนเส้นทางต้นแบบนี้Aหรือไม่? B, CและDทั้งหมดใช้การทำงานที่แตกต่างกัน แต่ที่พบบ่อยและผมต้องการที่AนำไปปฏิบัติIB, ICและIDเพราะมันหมายความว่าฉันสามารถผ่านในAตัวเองเป็นพึ่งพาการจับคู่การเชื่อมต่อเหล่านั้นและไม่ได้มีการเปิดเผยวิธีการช่วยเหลือด้านใน


คุณช่วยพูดอะไรเล็กน้อยเกี่ยวกับสาเหตุที่คุณต้องใช้คลาส A เพื่อใช้ IB, IC, ID ทำไมไม่เปิดเผย BCD ในที่สาธารณะ
Esben Skov Pedersen

1
ผมคิดว่าเหตุผลหลักของฉันสำหรับการเลือกAใช้IB, ICและIDมันเป็นความรู้สึกที่เหมาะสมมากขึ้นเพื่อเขียนPerson.Walk()เมื่อเทียบกับPerson.WalkHelper.Walk()ตัวอย่างเช่น
Nick Udell

คำตอบ:


7

สิ่งที่คุณกำลังมองหาเรียกว่ามิกซ์อิน น่าเศร้าที่ C # ไม่สนับสนุนสิ่งเหล่านั้น

มีวิธีการแก้ปัญหาบางประการที่: หนึ่ง , สอง , สาม , และอื่น ๆ อีกมากมาย

ฉันชอบอันสุดท้ายจริงๆ ความคิดในการใช้คลาสบางส่วนที่สร้างขึ้นโดยอัตโนมัติเพื่อสร้างหม้อไอน้ำน่าจะใกล้เคียงที่สุดคุณจะได้รับทางออกที่ดี:

[pMixins] เป็นปลั๊กอิน Visual Studio ที่สแกนโซลูชันสำหรับคลาสบางส่วนที่ตกแต่งด้วยแอตทริบิวต์ pMixin ด้วยการทำเครื่องหมายบางส่วนของชั้นเรียน [pMixins] สามารถสร้างไฟล์ behind รหัสและเพิ่มสมาชิกเพิ่มเติมในชั้นเรียนของคุณ


2

แม้ว่าจะไม่ลดรหัสสำเร็จรูปลง แต่ตอนนี้ Visual Studio 2015 มาพร้อมกับตัวเลือกการปรับโครงสร้างใหม่เพื่อสร้างแผ่นสำเร็จรูปให้คุณโดยอัตโนมัติ

หากต้องการใช้สิ่งนี้อันดับแรกให้สร้างส่วนต่อประสานIExampleและการใช้งานของExampleคุณ จากนั้นสร้างคลาสใหม่ของคุณCompositeและทำให้สืบทอดIExampleแต่ไม่ต้องใช้อินเทอร์เฟซ

เพิ่มคุณสมบัติหรือฟิลด์ประเภทExampleให้กับCompositeคลาสของคุณเปิดเมนูการดำเนินการด่วนบนโทเค็นIExampleในCompositeไฟล์คลาสของคุณและเลือก "ใช้อินเทอร์เฟซผ่าน 'ตัวอย่าง'" โดยที่ 'ตัวอย่าง' ในกรณีนี้คือชื่อของฟิลด์หรือคุณสมบัติ

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


1

ชั้นเรียนของคุณทำมากเกินไปนั่นเป็นเหตุผลที่คุณต้องติดตั้งหม้อไอน้ำมากขึ้น คุณพูดในความคิดเห็น:

มันให้ความรู้สึกที่สมเหตุสมผลในการเขียน Person.Walk () ซึ่งแตกต่างจาก Person.WalkHelper.Walk ()

ฉันไม่เห็นด้วย. การกระทำของการเดินเป็นแนวโน้มที่จะเกี่ยวข้องกับกฎระเบียบมากและไม่ได้อยู่ในPersonระดับ - มันเป็นในWalkingServiceชั้นเรียนด้วยวิธีการที่คนนำไปปฏิบัติwalk(IWalkable)IWalkable

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


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

4
สำหรับแนวคิดของwalk(IWalkable)วิธีการฉันไม่ชอบเป็นการส่วนตัวเพราะบริการเดินนั้นเป็นความรับผิดชอบของผู้โทรไม่ใช่ไม่ใช่บุคคลและไม่รับประกันความสม่ำเสมอ ผู้เรียกจะต้องทราบว่าบริการใดที่จะใช้เพื่อรับประกันความมั่นคงในขณะที่การรักษาไว้ในระดับบุคคลหมายความว่าจะต้องเปลี่ยนด้วยตนเองเพื่อให้พฤติกรรมการเดินแตกต่างกันในขณะที่ยังอนุญาตให้ผกผันพึ่งพาได้
Nick Udell

0

สิ่งที่คุณกำลังมองหาคือมรดกที่หลากหลาย อย่างไรก็ตามทั้ง C # และ Java ไม่มี

คุณสามารถขยาย B จาก A สิ่งนี้จะช่วยลดความต้องการเขตข้อมูลส่วนตัวสำหรับ B เช่นเดียวกับกาวเปลี่ยนเส้นทาง แต่คุณสามารถทำได้เพียงหนึ่งใน B, C หรือ D

ทีนี้ถ้าคุณสามารถสร้าง C ที่สืบทอดจาก B และ D จาก C คุณต้องมี A A ขยาย D ... ;) - เพื่อให้ชัดเจนแม้ว่าฉันไม่ได้กระตุ้นจริง ๆ ในตัวอย่างนี้เนื่องจากไม่มีข้อบ่งชี้ สำหรับมัน.

ใน C ++ คุณจะสามารถรับ A จาก B, C และ D ได้

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

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


2
คุณสามารถมีหลายการสืบทอดโดยใช้อินเตอร์เฟสในทั้ง java และ c # เช่นเดียวกับ op ที่ได้ทำในโค้ดตัวอย่างของเขา
Robert Harvey

1
บางคนอาจพิจารณาใช้อินเทอร์เฟซเหมือนกับหลายมรดก (ตามที่กล่าวใน C ++) คนอื่นจะไม่เห็นด้วยเนื่องจากอินเตอร์เฟสไม่สามารถแสดงวิธีการอินสแตนซ์ที่สืบทอดได้ซึ่งเป็นสิ่งที่คุณจะมีหากคุณมีหลายมรดก ใน C # คุณไม่สามารถขยายคลาสพื้นฐานหลายคลาสได้ดังนั้นคุณไม่สามารถสืบทอดการใช้วิธีอินสแตนซ์จากหลายคลาสได้ซึ่งเป็นสาเหตุที่คุณต้องใช้แผ่นสำเร็จรูปทั้งหมด ...
Erik Eidt

ผมยอมรับว่ามรดกหลายไม่ดี แต่ C # / ทางเลือกของ Java เดียวมรดกกับใช้อินเตอร์เฟซหลายไม่รักษาทั้งหมด (โดยไม่ต้องส่งต่ออินเตอร์เฟซมันเป็นฝันร้ายที่เหมาะกับการทำงาน) หลังจากใช้เวลาไปกับ Golang ฉันคิดว่า Go มีความคิดที่ถูกต้องเกี่ยวกับการไม่มีการสืบทอดใด ๆและแทนที่จะพึ่งพาองค์ประกอบทั้งหมดด้วยการส่งต่ออินเตอร์เฟส - แต่การใช้งานเฉพาะของพวกเขาก็มีปัญหาเช่นกัน ฉันคิดว่าทางออกที่ดีที่สุด (ซึ่งดูเหมือนว่าจะไม่มีใครนำไปปฏิบัติ) คือการจัดองค์ประกอบพร้อมการส่งต่อพร้อมความสามารถในการใช้ประเภทใดก็ได้เป็นส่วนต่อประสาน
ได
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.