Bir arayüzü nasıl geliştirir ve değiştirirsiniz?


22

Arayüzünüz olduğunu söyleyin IFoo:

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

API'nizin 2. sürümünde, Glargbu arayüze bir yöntem eklemeniz gerekir . Bunu, mevcut API kullanıcılarınızı kırmadan ve geriye dönük uyumluluğu koruyarak nasıl yaparsınız? Bu temel olarak .NET'e yöneliktir, ancak diğer çerçevelere ve dillere de uygulanabilir.


Sorunsuz bir şekilde ekleyebilirsiniz. Zaten orada olan bir şeyi değiştirdiğinizde / kaldırdığınızda problemler ortaya çıkar.
Rig

1
@Rig: En azından C # 'da, bir arabirime bir yöntem eklerseniz ve onu bu arabirimi uygulayan sınıflara eklemiyorsanız derleme hatası alırsınız.
Malice

Bu doğru. Bir yöntem imzasını değiştirmek veya silmek yerine, en az kargaşalı olabilecek kullanıcı sınıfı senaryosundan daha fazlasını düşünüyordum. Bu yüzden, arayüzünüze eklemeniz gerekirse, bunun biraz işe yarayabileceğini varsayalım.
Rig

Yanıtlar:


9

API'nizin 2. sürümünde, Glargbu arayüze bir yöntem eklemeniz gerekir .

Niye ya?

Bir API ile kullanım için tanımlanan arayüzlerin tamamen farklı iki rolü vardır:

  1. Bağımlılık inversiyonu - bu tür arayüzler API'niz tarafından tüketilir. İstemci kodunun eklentiler oluşturmasını sağlar.
  2. Soyutlama - bu tür arayüzler API'niz tarafından döndürülür ve döndürülen nesnelerin uygulama ayrıntılarını gizler.

Şimdi bir API'nin belirli bir sürümü için , aynı arayüz her ikisi gibi davranabilir. Yine de, gelecek sürümlerde, bu ayrılabilir.

  1. Tükettiğin arayüzden daha fazla bilgi çıkarmak istiyorsun. Performansı artırmak veya esneklik veya başka bir şey eklemek için. Muhtemelen eskisinden türetilmiş yeni bir arayüz tanımlayın ve onu tüketen ayrı bir yöntem oluşturun. AFAIK çoğu .NET dilinde yöntem aşırı yüklenmesine izin verir, bu yüzden fazla dağınıklık olmadan gerçekleşebilir.
  2. API’nizden “daha ​​zengin” bir nesnenin soyutlamasını, yani “daha ​​fazla geri” döndürmek istiyorsunuz. Burada iki seçeneğin var:

    • Müşteri kodunun arayüzün kendi uygulayıcılarına sahip olmayacağını makul bir şekilde kabul edebilirsiniz. Bu varsayım altında, uzantılarınızı mevcut arayüze eklemek güvenlidir.
    • Mümkünse öncekinden türetilmiş yeni bir arayüz tanımlayın. Eğer böyle bir türev imkansız ise, yeni arayüzün örneklerini sorgulamak için ayrı yöntemler oluşturun veya kompozisyon kullanın:

      interface MyNewInterface extends MyOldInterface { 
           FancyNewInterface getFancyShit();
      }
      

15

DirectX, arayüzlerine sürüm numaraları ekledi. Senin durumunda, çözüm gibi bir şey olurdu

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

API, hala IFoo'ya ve IFoo2'ye yalnızca IFoo2 işlevselliğinin gerekli olduğu yöntemlerde vb.

API uygulaması, bir IFoo parametre nesnesinin, IFoo2 için yöntem anlamının farklı olması durumunda, IFoo2 nesnesinin gerçekte IFoo2'yi uygulayıp uygulamadığını kontrol etmelidir.


3

API'nize yeni bir yöntem (veya yöntemler) eklemek, mevcut API üzerinde herhangi bir yan etkisi olmayacak şekilde yapılmalıdır. En önemlisi, eski API'yi yeni API yokmuş gibi kullanmaya devam eden birinin bundan etkilenmemesi gerekir. Eski API'yi kullanmanın da yeni API üzerinde beklenmeyen bir yan etkisi olmamalıdır .

API'deki mevcut yöntemlerden herhangi biri yenileriyle değiştiriliyorsa, bunları hemen kaldırmayın. Bunları kullanımdan kaldırılmış olarak işaretleyin ve ne kullanılması gerektiği konusunda bir açıklama yapın. Bu kod kullanıcılarınıza gelecekteki sürümlerin uyarmadan kodlarını kırmak yerine artık desteklemeyebileceğini bildirir.

Yeni ve eski API'ler uyumsuzsa ve istenmeyen yan etkiler olmadan birlikte yaşayamazsa, bunları ayırın ve yeni API kabul edilecekse eski API'nin tamamen emekli olması gerektiğini belgeleyin. Her ikisini de kullanmaya çalışan ve çalışmadığı zaman sinir bozan biri olacağı için bu daha az arzu edilir.

Özellikle .NET ile ilgili sorular sorduğunuzdan , (aşağıdaki örnekte kullanılan) 'a bağlantı veren .NET'teki değer kaybı hakkında bu makaleyi okumak isteyebilirsiniz 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

Genel arayüz değişiklikleri kırılmayı içerir. Ortak strateji, bunları yalnızca büyük sürümlerde ve donma süresinden sonra yapmaktır (bu nedenle heves içinde olmaz). Sizi yeni bir arayüze eklemeler ekliyorsanız (ve uygulamanız her ikisini de aynı sınıfa sağlayabilir) müşterilerinizi kırmadan kurtulabilirsiniz. Bu ideal değil ve yapmaya devam ederseniz bir karmaşa yaşarsınız.

Yine de başka türlü değişikliklerde (yöntemlerin kaldırılması, imzaların değiştirilmesi) sıkışmış durumdasınız.


2
Gelecekteki yöntem adları için bir ön ek ayırtabilir ve tüm kullanıcıları bu ad alanını kullanmamaları gerektiği, ancak bir inelegant API için yaptıkları konusunda uyarabilirsiniz. Yöntemlerin kaldırılması (ve genellikle toplama): Genel olarak, ebeveyn kesinlikle doğru olduğunu edecektir mevcut kullanıcıları kırmak ve bunu akıllıca planı dışında bunun için yapabileceğim bir şey yok.
Kilian Foth

1

Bir arayüz bir sözleşmedir, bu yüzden versiyonlamaya sahip olmamalıdır. Bir futbolcu yeni bir sözleşme yaparsa ne olur? Eskisi hala geçerli mi? Hayır. Arayüz değiştirilirse, sözleşme değişir ve önceki sözleşme (arayüz) artık geçerli değildir.

IFoo2 stratejisini kullanabilseniz de, nihayetinde bu durum dağınık olacak:

  • IFoo2
  • IFoo3
  • IFoo4
  • vb.

Yuck.

Bir API farklı. Kullanmak için kod kütüphanesi veriyorum. Gelecek ay size güncellenmiş bir kütüphane veriyorum. Başka bir posterin dediği gibi, zaten kullandığımı kırma, sadece yeni işlevler / yöntemler ekle.

Bir şeyi sürümlendirmek istiyorsanız, arayüz yerine bir abtract sınıfı kullanın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.