อะไรคือเหตุผลที่ดีในการใช้งานส่วนติดต่ออย่างชัดเจนเพื่อจุดประสงค์ในการซ่อนสมาชิก


11

ระหว่างที่ฉันศึกษาเรื่องความซับซ้อนของ C # ฉันพบข้อความที่น่าสนใจเกี่ยวกับการใช้อินเทอร์เฟซที่ชัดเจน

While this syntax is quite helpful when you need to resolve name clashes, you can use explicit interface implementation simply to hide more "advanced" members from the object level.

ความแตกต่างระหว่างการอนุญาตให้ใช้object.method()หรือต้องการการหล่อของ((Interface)object).method()การทำให้งงงวยหมายถึงใจแข็งกับสายตาที่ไม่มีประสบการณ์ของฉัน ข้อความตั้งข้อสังเกตว่าสิ่งนี้จะซ่อนวิธีการจาก Intellisense ที่ระดับวัตถุ แต่ทำไมคุณต้องการทำเช่นนั้นหากไม่จำเป็นต้องหลีกเลี่ยงความขัดแย้งของชื่อ


คำตอบ:


12

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

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


6
มันเป็นเพียงฉันหรือเสียงนี้เป็นความคิดที่น่ากลัว?
Kevin Peno

5
@ เควินทำไมเหรอ? บางครั้งอินเทอร์เฟซไม่อยู่ในความควบคุมของคุณและคุณต้องใช้มัน การลดความเสียหายของอินเทอร์เฟซแบบเอาแต่ใจดูเหมือนว่าสมเหตุสมผล
Chris Pitman

1
+1 สำหรับชี้ให้เห็นว่าหลายครั้งที่โลกแห่งความเป็นจริงได้รับในทางที่ถูกต้องในการทำสิ่งต่าง ๆ @ Kevin ใช่มันเป็นความคิดที่น่ากลัว แต่บางครั้งคุณไม่ได้มีทางเลือกและมีการทำงานร่วมกับเลอะ - ดีกว่าที่จะซ่อนมันออกไปและทำให้ซุ้มของการทำสิ่งที่ถูกต้องเมื่อคุณไม่สามารถจริงๆทำมันถูกต้อง
Wayne Molina

@ Wayne ฉันเข้าใจเหตุผลที่คุณต้องการ / ใช้ระบบดังกล่าว นรกฉันอาจใช้มันในกรณีที่คุณระบุไว้ ฉันเดาว่าความคิดเห็นสั้น ๆ ของฉันเป็นเพียงชี้ให้เห็นว่านี่เป็นสิ่งที่ไม่เหมาะสมดังนั้นทำไมอนุญาตให้ใช้ในภาษา
Kevin Peno

1
การแยกอินเทอร์เฟซที่มากเกินไปอาจเป็นอุปสรรคสำคัญต่อการจัดองค์ประกอบและการรวมตัว ยกตัวอย่างเช่นพิจารณาว่าเราปรารถนาที่จะมีการนำไปปฏิบัติIEnumerable<T>ซึ่งเป็นการเชื่อมต่อของอีกสองคน หากIEnumerable<T>รวมคุณสมบัติที่จะบอกว่าการนับเป็นที่รู้จักอาจไม่มีที่สิ้นสุดหรือไม่พร้อมกับวิธีการถามว่าการนับเป็นคลาสที่รวมหลายรายการIEnumerable<T>และทำงานเป็นการต่อข้อมูลได้อย่างมีประสิทธิภาพสามารถรายงานจำนวนในกรณีที่บางส่วนของ คอลเลกชันที่ห่อหุ้มรู้จำนวนของพวกเขา
supercat

4

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

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

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

ตัวอย่าง:

public class Factory
{
    // factory method to create a hard-coded Mazda Tribute car.
    public static Car CreateCar()
    {
        Car car = new Car();

        // the Factory class can modify the model because it has access to
        // the private ICarSetters interface
        ((ICarSetters)car).model = "Mazda Tribute";

        return car;
    }

    // define a private interface containing the setters.
    private interface ICarSetters
    {
        // define the setter in the private interface
        string model { set; }
    }

    // This is the inner class. It has a member "model" that should not be modified
    // but clients, but should be modified by the factory.
    public class Car: ICarSetters
    {
        // explicitly implement the setter
        string ICarSetters.model { set; }

        // create a public getter
        public string model { get; }
    }
}

class Client
{
    public Client()
    {
        Factory.Car car = Factory.CreateCar();

        // can only read model because only the getter is public
        // and ICarSetters is private to Factory
        string model = car.model;
    }
}

นั่นคือสิ่งที่ฉันจะใช้อินเทอร์เฟซที่ชัดเจนสำหรับ


3

หากคลาสใช้อินเทอร์เฟซสองตัวที่ประกอบด้วยสมาชิกที่มีลายเซ็นเดียวกันดังนั้นการใช้สมาชิกนั้นในคลาสจะทำให้ทั้งสองอินเตอร์เฟสใช้สมาชิกนั้นเป็นการใช้งาน ในตัวอย่างต่อไปนี้การเรียกทั้งหมดเพื่อPaintเรียกใช้วิธีการเดียวกัน ค#

class Test 
{
    static void Main()

    {
        SampleClass sc = new SampleClass();
        IControl ctrl = (IControl)sc;
        ISurface srfc = (ISurface)sc;

        // The following lines all call the same method.
        sc.Paint();
        ctrl.Paint();
        srfc.Paint();
    }
}


interface IControl
{
    void Paint();
}
interface ISurface
{
    void Paint();
}
class SampleClass : IControl, ISurface
{
    // Both ISurface.Paint and IControl.Paint call this method. 
    public void Paint()
    {
        Console.WriteLine("Paint method in SampleClass");
    }
}

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


1

อินเทอร์เฟซที่ชัดเจนมีประโยชน์เมื่อวัตถุมีรูปแบบการสื่อสารที่แตกต่างกันสองรูปแบบหรือมากกว่า

ตัวอย่างเช่นวัตถุที่รักษาชุดของวัตถุลูกที่ต้องสื่อสารกับผู้ปกครอง

มีการกระทำบางอย่างที่เราต้องการให้ผู้โทรภายนอกเข้าถึงได้และการกระทำบางอย่างที่เราต้องการให้เข้าถึงได้เฉพาะกับวัตถุลูก

อินเทอร์เฟซที่ชัดเจนช่วยให้มั่นใจว่าการแบ่งนี้

    static void Main(string[] args)
    {
        var parent = new Parent();
        parent.DoExternalStuff();
    }

    interface IExternal {
        void DoExternalStuff();
    }

    interface IInternal {
        void DoInternalStuff();
    }

    class Parent : IExternal, IInternal
    {
        public Parent()
        {
            var child = new Child(this);
        }

        public void DoExternalStuff()
        {
           // do something exciting here for external callers
        }

        void IInternal.DoInternalStuff()
        {
            // do something exciting here for internal callers
        }
    }

    class Child
    {
        public Child(IInternal parent)
        {
            parent.DoInternalStuff();
        }
    }

0

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

ทำไมคุณถึงทำเช่นนั้นแทนที่จะบอกว่า "อินเทอร์เฟซขั้นสูง" ตัวที่สองฉันไม่รู้


0

รหัสอ่านโดยทั่วไปมากกว่าที่เขียนและฉันเพียงใช้ Intellisense เพื่อเขียนโค้ดอย่างรวดเร็ว ฉันจะไม่เขียนโค้ดวิธีการเฉพาะเพื่อให้ Intellisense ดีกว่า

ฉันไม่ได้เห็นเป็นพิเศษ

วัตถุ (อินเทอร์เฟซ) .method () สามารถอ่านได้มากกว่า object.method ()

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

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