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


12

ฉันมีปัญหาการออกแบบเกี่ยวกับคุณสมบัติ. NET

interface IX
{
    Guid Id { get; }
    bool IsInvalidated { get; }
    void Invalidate();
}

ปัญหา:

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

สมมติว่ามันเป็นความตั้งใจของฉันที่จะทำให้ชัดเจนว่า ...

  • Id แทนค่าคงที่ (ซึ่งอาจถูกแคชอย่างปลอดภัย) ในขณะที่
  • IsInvalidatedอาจเปลี่ยนค่าในช่วงอายุของIXวัตถุ (และไม่ควรแคช)

ฉันจะปรับเปลี่ยนinterface IXเพื่อให้สัญญานั้นชัดเจนเพียงพอได้อย่างไร

ความพยายามสามข้อของฉันในการแก้ปัญหา:

  1. อินเตอร์เฟสได้รับการออกแบบมาอย่างดี การปรากฏตัวของวิธีการที่เรียกว่าInvalidate()ช่วยให้โปรแกรมเมอร์ที่จะอนุมานว่ามูลค่าของทรัพย์สินที่มีชื่อคล้ายกันIsInvalidatedอาจได้รับผลกระทบจากมัน

    อาร์กิวเมนต์นี้มีไว้เฉพาะในกรณีที่เมธอดและคุณสมบัติมีชื่อคล้ายกัน

  2. เพิ่มส่วนต่อประสานนี้กับกิจกรรมIsInvalidatedChanged:

    bool IsInvalidated { get; }
    event EventHandler IsInvalidatedChanged;

    สถานะของ…Changedเหตุการณ์สำหรับIsInvalidatedสถานะที่คุณสมบัตินี้อาจเปลี่ยนค่าและการไม่มีเหตุการณ์ที่คล้ายกันสำหรับIdเป็นสัญญาว่าคุณสมบัตินั้นจะไม่เปลี่ยนค่าของมัน

    ฉันชอบโซลูชันนี้ แต่มีสิ่งเพิ่มเติมมากมายที่อาจไม่ได้ใช้เลย

  3. แทนที่คุณสมบัติIsInvalidatedด้วยเมธอดIsInvalidated():

    bool IsInvalidated();

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

    ใช้เมธอดแทนคุณสมบัติในสถานการณ์ต่อไปนี้ […] การดำเนินการจะส่งกลับผลลัพธ์ที่แตกต่างกันในแต่ละครั้งที่มีการเรียกใช้แม้ว่าพารามิเตอร์จะไม่เปลี่ยนแปลง

ฉันคาดหวังคำตอบแบบไหน?

  • ฉันสนใจมากที่สุดในการแก้ปัญหาที่แตกต่างอย่างสิ้นเชิงพร้อมกับคำอธิบายว่าพวกเขาเอาชนะความพยายามของฉันได้อย่างไร

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

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

  • อย่างน้อยที่สุดฉันต้องการคำติชมเกี่ยวกับวิธีแก้ปัญหาที่คุณต้องการและเหตุผลอะไรบ้าง


ไม่IsInvalidatedต้องการprivate setหรือ
James

2
@James: ไม่จำเป็นต้องไม่อยู่ในประกาศอินเตอร์เฟซหรือในการดำเนินงาน:class Foo : IFoo { private bool isInvalidated; public bool IsInvalidated { get { return isInvalidated; } } public void Invalidate() { isInvalidated = true; } }
stakx

@James Properties ในอินเตอร์เฟสไม่เหมือนกับคุณสมบัติอัตโนมัติแม้ว่าจะใช้ไวยากรณ์เดียวกัน
svick

ฉันสงสัยว่าอินเทอร์เฟซ "มีพลัง" เพื่อกำหนดพฤติกรรมดังกล่าวหรือไม่? พฤติกรรมนี้ไม่ควรมอบให้กับการใช้งานแต่ละครั้ง ฉันคิดว่าถ้าคุณต้องการบังคับใช้สิ่งต่าง ๆ ในระดับนั้นคุณควรพิจารณาสร้างคลาสนามธรรมเพื่อให้ subtypes นั้นสืบทอดมาจากมัน (โดยเหตุผลแล้วเหตุผลของฉันไม่สมเหตุสมผล)
heltonbiker

@heltonbiker แต่น่าเสียดายที่ภาษาส่วนใหญ่ (ฉันรู้) ไม่อนุญาตให้มีการแสดงความข้อ จำกัด ดังกล่าวในประเภท แต่พวกเขาแน่นอนควร นี่เป็นเรื่องของข้อกำหนดไม่ใช่การนำไปปฏิบัติ ในการเลือกของฉันสิ่งที่ขาดหายไปคือความเป็นไปได้ในการแสดงค่าคงที่ของชั้นเรียนและเงื่อนไขหลังตรงในภาษา เป็นการดีที่เราไม่ควรกังวลเกี่ยวกับInvalidStateExceptionตัวอย่างเช่น แต่ฉันไม่แน่ใจว่าสิ่งนี้เป็นไปได้ในทางทฤษฎีหรือไม่ จะดี แต่
proskor

คำตอบ:


2

ฉันต้องการโซลูชัน 3 มากกว่า 1 และ 2

ปัญหาของฉันสำหรับโซลูชัน 1 คือ : จะเกิดอะไรขึ้นหากไม่มีInvalidateวิธี สมมติอินเตอร์เฟซที่มีนักการIsValidทรัพย์สินที่ผลตอบแทนDateTime.Now > MyExpirationDate; คุณอาจไม่ต้องการSetInvalidวิธีการที่ชัดเจนที่นี่ เกิดอะไรขึ้นถ้าวิธีการส่งผลกระทบต่อคุณสมบัติหลาย ๆ สมมติว่าประเภทการเชื่อมต่อด้วยIsOpenและIsConnectedคุณสมบัติ - ทั้งคู่ได้รับผลกระทบจากCloseวิธีการ

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

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

โซลูชันที่ 3คือสิ่งที่ฉันจะทำ ตามที่กล่าวไว้ใน aviv สิ่งนี้อาจใช้ได้กับนักพัฒนา C # เท่านั้น สำหรับฉันในฐานะ C # -dev ความจริงที่IsInvalidatedไม่ใช่ทรัพย์สินจะสื่อถึงความหมายของ "นั่นไม่ใช่เพียงแค่ accessor ที่เรียบง่าย แต่มีอะไรบางอย่างเกิดขึ้นที่นี่" สิ่งนี้ไม่ได้ใช้กับทุกคนและตามที่ MainMa ชี้ให้เห็นกรอบงาน. NET นั้นไม่สอดคล้องกันที่นี่

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

ดังนั้นคำแนะนำของฉันจะเป็น:

ประกาศโซลูชัน 3 ข้อตกลงและปฏิบัติตามอย่างเคร่งครัด ทำให้ชัดเจนในเอกสารประกอบของคุณสมบัติว่าคุณสมบัติมีการเปลี่ยนแปลงค่าหรือไม่ นักพัฒนาที่ทำงานกับคุณสมบัติที่เรียบง่ายจะถือว่าพวกเขาไม่เปลี่ยนแปลง (เช่นเปลี่ยนเฉพาะเมื่อสถานะวัตถุถูกแก้ไข) นักพัฒนาเผชิญหน้ากับวิธีการที่เสียงเหมือนมันอาจจะเป็นคุณสมบัติที่ ( Count(), Length(), IsOpen()) รู้ว่า someting ของที่เกิดขึ้นและ (หวังว่า) อ่านเอกสารวิธีการที่จะเข้าใจสิ่งที่ว่าวิธีการที่ไม่และวิธีการทำงาน


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

8

มีวิธีที่สี่คือ: พึ่งพาเอกสาร

คุณจะรู้ได้อย่างไรว่าstringคลาสนั้นไม่เปลี่ยนรูป? คุณเพียงแค่รู้ว่าเพราะคุณได้อ่านเอกสาร MSDN StringBuilderในทางกลับกันไม่สามารถเปลี่ยนแปลงได้เพราะอีกครั้งเอกสารบอกคุณว่า

/// <summary>
/// Represents an index of an element stored in the database.
/// </summary>
private interface IX
{
    /// <summary>
    /// Gets the immutable globally unique identifier of the index, the identifier being
    /// assigned by the database when the index is created.
    /// </summary>
    Guid Id { get; }

    /// <summary>
    /// Gets a value indicating whether the index is invalidated, which means that the
    /// indexed element is no longer valid and should be reloaded from the database. The
    /// index can be invalidated by calling the <see cref="Invalidate()" /> method.
    /// </summary>
    bool IsInvalidated { get; }

    /// <summary>
    /// Invalidates the index, without forcing the indexed element to be reloaded from the
    /// database.
    /// </summary>
    void Invalidate();
}

วิธีการแก้ปัญหาที่สามของคุณไม่ได้เลวร้าย แต่ .NET Framework ไม่ได้ทำตามนั้น ตัวอย่างเช่น:

StringBuilder.Length
DateTime.Now

เป็นคุณสมบัติ แต่ไม่คาดหวังให้คงที่ทุกครั้ง

สิ่งที่ใช้อย่างสม่ำเสมอใน. NET Framework นั้นคือ:

IEnumerable<T>.Count()

เป็นวิธีการในขณะที่:

IList<T>.Length

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


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

public class Product
{
    private readonly int price;

    public Product(int price)
    {
        this.price = price;
    }

    public int Price
    {
        get
        {
            return this.price;
        }
    }
}

มีความชัดเจน: ราคาจะยังคงเหมือนเดิม

น่าเศร้าที่คุณไม่สามารถใช้รูปแบบเดียวกันกับอินเทอร์เฟซและเนื่องจาก C # ไม่สามารถแสดงออกได้เพียงพอในกรณีดังกล่าวควรใช้เอกสาร (รวมถึงเอกสาร XML และแผนภาพ UML) เพื่อปิดช่องว่าง


แม้แต่แนวทาง“ ไม่มีงานเพิ่มเติม” ก็ไม่ได้ใช้อย่างสม่ำเสมอ ตัวอย่างเช่นLazy<T>.Valueอาจใช้เวลานานในการคำนวณ (เมื่อเข้าถึงเป็นครั้งแรก)
svick

1
ในความคิดของฉันมันไม่สำคัญว่าถ้า. NET Framework ตามหลักการของการแก้ปัญหา 3 ฉันคาดหวังว่านักพัฒนาจะฉลาดพอที่จะรู้ว่าพวกเขากำลังทำงานกับประเภทหรือประเภทของกรอบภายในหรือไม่ ผู้พัฒนาที่ไม่ทราบว่าไม่ได้อ่านเอกสารดังนั้นการแก้ไข 4 ก็ไม่ช่วยเช่นกัน หากมีการนำโซลูชัน 3 มาใช้เป็นรูปแบบ บริษัท / ทีมฉันเชื่อว่าไม่สำคัญว่า API อื่น ๆ จะติดตามด้วยหรือไม่ (แม้ว่าจะได้รับการชื่นชมอย่างมากแน่นอน)
enzi

4

2 เซนต์ของฉัน:

ตัวเลือก 3: ในฐานะที่ไม่ใช่ C # -er มันจะไม่เป็นเงื่อนงำมากนัก อย่างไรก็ตามการตัดสินโดยคำพูดที่คุณนำมาควรมีความชัดเจนสำหรับโปรแกรมเมอร์ C # ที่มีความเชี่ยวชาญซึ่งหมายถึงบางสิ่ง คุณควรเพิ่มเอกสารเกี่ยวกับสิ่งนี้แม้ว่า

ตัวเลือกที่ 2: หากคุณไม่ต้องการเพิ่มกิจกรรมในทุกสิ่งที่อาจเปลี่ยนแปลงอย่าไปที่นั่น

ตัวเลือกอื่น:

  • การเปลี่ยนชื่ออินเตอร์เฟส IXMutable ดังนั้นจึงชัดเจนว่าสามารถเปลี่ยนสถานะได้ ค่าที่ไม่เปลี่ยนรูปเพียงอย่างเดียวในตัวอย่างของคุณคือidซึ่งมักจะถือว่าไม่สามารถเปลี่ยนแปลงได้แม้ในวัตถุที่ไม่แน่นอน
  • ไม่พูดถึงมัน อินเทอร์เฟซไม่ดีพอที่จะอธิบายพฤติกรรมตามที่เราต้องการ ส่วนหนึ่งเป็นเพราะภาษาไม่ได้ให้คุณอธิบายสิ่งต่าง ๆ อย่างเช่น "วิธีนี้จะส่งกลับค่าเดิมสำหรับวัตถุที่ระบุเสมอ" หรือ "การเรียกวิธีนี้ด้วยอาร์กิวเมนต์ x <0 จะทำให้เกิดข้อยกเว้น"
  • ยกเว้นว่ามีกลไกในการขยายภาษาและให้ข้อมูลที่แม่นยำมากขึ้นเกี่ยวกับโครงสร้าง - คำอธิบายประกอบ / คุณลักษณะ บางครั้งพวกเขาต้องการงานบางอย่าง แต่อนุญาตให้คุณระบุสิ่งที่ซับซ้อนโดยพลการเกี่ยวกับวิธีการของคุณ ค้นหาหรือคิดค้นคำอธิบายประกอบที่ระบุว่า "คุณค่าของวิธีการ / คุณสมบัตินี้สามารถเปลี่ยนแปลงได้ตลอดอายุการใช้งานของวัตถุ" และเพิ่มลงในวิธีการ คุณอาจต้องเล่นลูกเล่นบางอย่างเพื่อให้ได้วิธีการนำไปใช้เพื่อ "สืบทอด" และผู้ใช้อาจจำเป็นต้องอ่านเอกสารสำหรับคำอธิบายประกอบนั้น แต่มันจะเป็นเครื่องมือที่ช่วยให้คุณสามารถพูดสิ่งที่คุณต้องการพูดแทนการบอกใบ้ ที่มัน

3

อีกตัวเลือกหนึ่งที่จะแยกอินเตอร์เฟซ: สมมติว่าหลังจากเรียกInvalidate()ภาวนาของทุกIsInvalidatedควรกลับค่าเดียวกันtrueมีดูเหมือนว่าจะไม่มีเหตุผลที่จะเรียกส่วนเดียวกันซึ่งเรียกIsInvalidatedInvalidate()

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

interface Invalidatable
{
    bool IsInvalidated { get; }
}

ฉันรู้ว่านี่ไม่ได้ตอบคำถามโดยตรง แต่อย่างน้อยก็ช่วยลดคำถามที่ว่าจะทำเครื่องหมายบางประเภทไม่เปลี่ยนรูปซึ่งเป็นปัญหาที่เข้าใจกันทั่วไปและเงียบ ตัวอย่างเช่นสมมติว่าทุกประเภทสามารถเปลี่ยนแปลงได้เว้นแต่จะกำหนดไว้เป็นอย่างอื่นคุณสามารถสรุปได้ว่าอินเทอร์เฟซที่สอง ( IsInvalidated) นั้นไม่แน่นอนและดังนั้นจึงสามารถเปลี่ยนค่าได้เป็นIsInvalidatedครั้งคราว ในทางกลับกันสมมติว่าอินเทอร์เฟซแรกมีลักษณะเช่นนี้ (pseudo-syntax):

[Immutable]
interface IX
{
    Guid Id { get; }
    void Invalidate();
}

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


ไม่ใช่ความคิดที่เลว! อย่างไรก็ตามฉันจะยืนยันว่ามันเป็นความผิดที่จะทำเครื่องหมายส่วนต่อประสาน[Immutable]ตราบใดที่มันครอบคลุมวิธีการที่มีจุดประสงค์เดียวที่จะทำให้เกิดการกลายพันธุ์ ฉันจะย้ายInvalidate()วิธีการไปยังInvalidatableอินเทอร์เฟซ
stakx

1
@stakx ฉันไม่เห็นด้วย :) ฉันคิดว่าคุณสร้างความสับสนให้กับแนวคิดเรื่องความไม่เปลี่ยนแปลงและความบริสุทธิ์ (ไม่มีผลข้างเคียง) ในความเป็นจริงจากมุมมองของอินเทอร์เฟซที่เสนอ IX ไม่มีการกลายพันธุ์ที่สังเกตได้ทั้งหมด เมื่อใดก็ตามที่คุณโทรIdคุณจะได้รับค่าเดียวกันทุกครั้ง เช่นเดียวกับInvalidate()(คุณไม่ได้รับอะไรเลยเนื่องจากเป็นประเภทส่งคืนvoid) ดังนั้นประเภทนี้ไม่เปลี่ยนรูป แน่นอนว่าคุณจะมีผลข้างเคียงแต่คุณจะไม่สามารถที่จะสังเกตพวกเขาผ่านทางอินเตอร์เฟซเพื่อให้พวกเขาจะไม่ได้มีผลกระทบต่อลูกค้าของIX IX
proskor

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

(ฉันเข้าใจว่าในสถานการณ์โลกแห่งความเป็นจริงลักษณะของอินเทอร์เฟซแบบแยกอาจขึ้นกับกรณีการใช้งานจริงมากกว่าเรื่องทางเทคนิค แต่ฉันพยายามเข้าใจเหตุผลของคุณอย่างเต็มที่ที่นี่)
stakx

1
@stakx ก่อนอื่นคุณถามถึงความเป็นไปได้ที่จะทำให้ซีแมนติกของอินเทอร์เฟซของคุณชัดเจนขึ้น ความคิดของฉันคือการลดปัญหาที่ไม่สามารถเปลี่ยนแปลงได้ซึ่งต้องแยกอินเทอร์เฟซ แต่ไม่เพียงแค่เป็นแยกที่จำเป็นเพื่อให้เปลี่ยนรูปหนึ่งอินเตอร์เฟซก็ยังจะทำให้รู้สึกดีเพราะมีเหตุผลที่จะเรียกทั้งไม่มีInvalidate()และIsInvalidatedโดยเดียวกันผู้บริโภคของอินเตอร์เฟซ หากคุณโทรInvalidate()คุณควรรู้ว่ามันกลายเป็นโมฆะดังนั้นทำไมต้องตรวจสอบดู ดังนั้นคุณสามารถให้สองอินเตอร์เฟสที่แตกต่างกันเพื่อวัตถุประสงค์ที่แตกต่างกัน
proskor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.