คุณพัฒนาและปรับรุ่นอินเทอร์เฟซอย่างไร


22

สมมติว่าคุณมีอินเทอร์เฟซIFoo:

public interface IFoo {
    void Bar(string s);
    int Quux(object o);
}

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


คุณสามารถเพิ่มได้โดยไม่มีปัญหา ปัญหาเกิดขึ้นเมื่อคุณเปลี่ยน / ลบสิ่งที่มีอยู่แล้ว
Rig

1
@Rig: อย่างน้อย C # คุณจะได้รับข้อผิดพลาดในการคอมไพล์หากคุณเพิ่มวิธีการในส่วนต่อประสานและไม่เพิ่มเข้าไปในชั้นเรียนที่ใช้ส่วนต่อประสานนั้น
Malice

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

คำตอบ:


9

ใน API รุ่นที่ 2 ของคุณคุณจะต้องเพิ่มวิธีGlargการในอินเทอร์เฟซนี้

ทำไม?

อินเตอร์เฟสที่กำหนดไว้สำหรับใช้กับ API มีบทบาทที่แตกต่างกันสองประการ:

  1. การพึ่งพาการพึ่งพา - อินเทอร์เฟซดังกล่าวถูกใช้โดย API ของคุณ พวกเขาอนุญาตให้รหัสลูกค้าในการสร้างปลั๊กอิน ฯลฯ
  2. Abstraction - อินเทอร์เฟซดังกล่าวถูกส่งคืนโดย API ของคุณและซ่อนรายละเอียดการใช้งานของวัตถุที่ส่งคืน

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

  1. คุณต้องการดึงข้อมูลเพิ่มเติมจากส่วนต่อประสานที่คุณใช้ เพื่อเพิ่มประสิทธิภาพหรือเพิ่มความยืดหยุ่นหรืออะไรก็ตาม กำหนดอินเทอร์เฟซใหม่ซึ่งอาจมาจากอินเทอร์เฟซเก่าและสร้างวิธีการแยกต่างหากที่ใช้งาน ภาษา AFAIK ส่วนใหญ่. NET อนุญาตวิธีการโอเวอร์โหลดดังนั้นสิ่งนี้สามารถเกิดขึ้นได้โดยไม่ต้องเพิ่มความยุ่งเหยิงมาก
  2. คุณต้องการที่จะ "คืนมากขึ้น" เช่นการลบวัตถุ "ยิ่งขึ้น" จาก API ของคุณ ที่นี่คุณมีสองทางเลือก:

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

      interface MyNewInterface extends MyOldInterface { 
           FancyNewInterface getFancyShit();
      }
      

15

DirectX เพิ่มหมายเลขรุ่นให้กับส่วนต่อประสาน ในกรณีของคุณการแก้ปัญหาจะเป็นอย่างไร

public interface IFoo2 : IFoo
{
    void Glarg();
}

API จะยังคงอ้างถึง IFoo และ IFoo2 เฉพาะในวิธีการอื่น ๆ ที่จำเป็นต้องใช้ฟังก์ชั่น IFoo2

การใช้ API ควรตรวจสอบวิธีการที่มีอยู่ (= รุ่น 1) ว่าวัตถุ IFoo พารามิเตอร์ใช้ IFoo2 จริงหรือไม่ถ้าความหมายของวิธีการนั้นแตกต่างกันสำหรับ IFoo2


3

การเพิ่มวิธีการใหม่ (หรือวิธีการ) ใน API ของคุณควรทำในลักษณะที่ไม่มีผลข้างเคียงใด ๆ กับ API ที่มีอยู่ สิ่งสำคัญที่สุดคือคนที่ยังคงใช้ API เก่าต่อไปราวกับว่าไม่มี API ใหม่ควรได้รับผลกระทบ การใช้ API เก่าไม่ควรมีผลข้างเคียงที่ไม่คาดคิดกับ API ใหม่

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

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

เนื่องจากคุณถามเกี่ยวกับ. NET โดยเฉพาะคุณอาจต้องการอ่านบทความนี้เกี่ยวกับการคัดค้านใน. NET ซึ่งลิงก์ไปยังObsoleteAttribute(ใช้ในตัวอย่างต่อไปนี้):

using System;

public sealed class App {
   static void Main() {      
      // The line below causes the compiler to issue a warning:
      // 'App.SomeDeprecatedMethod()' is obsolete: 'Do not call this method.'
      SomeDeprecatedMethod();
   }

   // The method below is marked with the ObsoleteAttribute. 
   // Any code that attempts to call this method will get a warning.
   [Obsolete("Do not call this method.")]
   private static void SomeDeprecatedMethod() { }
}

2

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

ด้วยการปรับเปลี่ยนประเภทอื่น (การลบวิธีการเปลี่ยนลายเซ็น) แสดงว่าคุณติดอยู่


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

1

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

แม้ว่าคุณจะสามารถใช้กลยุทธ์ IFoo2 ได้ แต่ท้ายที่สุดมันจะยุ่งเหยิงเมื่อคุณ:

  • IFoo2
  • IFoo3
  • IFoo4
  • เป็นต้น

yuck

API แตกต่างกัน ฉันให้รหัสห้องสมุดเพื่อใช้ เดือนหน้าฉันจะให้ห้องสมุดที่อัปเดตแก่คุณ อย่างที่ผู้โพสต์คนอื่นพูดไว้อย่าทำลายสิ่งที่ฉันใช้อยู่แล้วเพียงเพิ่มฟังก์ชัน / วิธีการใหม่ ๆ

ถ้าคุณต้องการรุ่นสิ่งใช้คลาส abtract แทนอินเทอร์เฟซ

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