Öğretici: Arabirimleri varsayılan arabirim yöntemleriyle güncelleştirme

Bir arabirimin üyesini bildirdiğinizde bir uygulama tanımlayabilirsiniz. En yaygın senaryo, zaten yayımlanmış ve sayısız istemci tarafından kullanılan bir arabirime üyeleri güvenli bir şekilde eklemektir.

Bu öğreticide aşağıdakilerin nasıl yapılacağını öğreneceksiniz:

  • Uygulamalarla yöntemler ekleyerek arabirimleri güvenli bir şekilde genişletin.
  • Daha fazla esneklik sağlamak için parametreli uygulamalar oluşturun.
  • Uygulayıcıların geçersiz kılma biçiminde daha özel bir uygulama sağlamasına olanak tanıyın.

Önkoşullar

C# derleyicisi de dahil olmak üzere makinenizi .NET'i çalıştıracak şekilde ayarlamanız gerekir. C# derleyicisi Visual Studio 2022 veya .NET SDK ile kullanılabilir.

Senaryoya genel bakış

Bu öğretici, müşteri ilişkileri kitaplığının 1. sürümüyle başlar. Başlangıç uygulamasını GitHub'da bulunan örnek depomuzdan alabilirsiniz. Bu kitaplığı oluşturan şirket, mevcut uygulamaları olan müşterilerin kitaplıklarını benimsemesini hedeflemiştir. Kitaplıklarının kullanıcılarına uygulayacakları en düşük arabirim tanımlarını sağladılar. Müşterinin arabirim tanımı şu şekildedir:

public interface ICustomer
{
    IEnumerable<IOrder> PreviousOrders { get; }

    DateTime DateJoined { get; }
    DateTime? LastOrder { get; }
    string Name { get; }
    IDictionary<DateTime, string> Reminders { get; }
}

Bir sırayı temsil eden ikinci bir arabirim tanımladılar:

public interface IOrder
{
    DateTime Purchased { get; }
    decimal Cost { get; }
}

Bu arabirimlerden ekip, kullanıcıları için bir kitaplık oluşturarak müşterileri için daha iyi bir deneyim oluşturabilir. Amaçları, mevcut müşterilerle daha derin bir ilişki oluşturmak ve yeni müşterilerle ilişkilerini geliştirmekti.

Şimdi kitaplığı bir sonraki sürüme yükseltmenin zamanı geldi. İstenen özelliklerden biri, çok sayıda siparişi olan müşteriler için sadakat indirimi sağlar. Bu yeni sadakat indirimi, müşteri sipariş yaptığında uygulanır. Belirli indirim, her müşterinin bir özelliğidir. uygulamasının ICustomer her uygulaması, bağlılık programı indirimi için farklı kurallar ayarlayabilir.

Bu işlevi eklemenin en doğal yolu, herhangi bir sadakat indirimi ICustomer uygulamak için bir yöntemle arabirimi geliştirmektir. Bu tasarım önerisi deneyimli geliştiriciler arasında endişeye neden oldu: "Arabirimler piyasaya sürüldükten sonra sabittir! Hataya neden olan bir değişiklik yapmayın!" Arabirimleri yükseltmek için varsayılan arabirim uygulamalarını kullanmanız gerekir. Kitaplık yazarları arabirime yeni üyeler ekleyebilir ve bu üyeler için varsayılan bir uygulama sağlayabilir.

Varsayılan arabirim uygulamaları, geliştiricilerin bir arabirimi yükseltmesine olanak tanırken herhangi bir uygulayıcının bu uygulamayı geçersiz kılmasını sağlar. Kitaplığın kullanıcıları varsayılan uygulamayı hataya neden olmayan bir değişiklik olarak kabul edebilir. İş kuralları farklıysa geçersiz kılabilir.

Varsayılan arabirim yöntemleriyle yükseltme

Ekip, en olası varsayılan uygulama konusunda anlaştı: müşteriler için sadakat indirimi.

Yükseltme, iki özellik ayarlama işlevi sağlamalıdır: indirime uygun olması için gereken sipariş sayısı ve indirim yüzdesi. Bu özellikler, bunu varsayılan arabirim yöntemleri için mükemmel bir senaryo haline getirir. Arabirimine ICustomer bir yöntem ekleyebilir ve en olası uygulamayı sağlayabilirsiniz. Tüm mevcut uygulamalar ve tüm yeni uygulamalar varsayılan uygulamayı kullanabilir veya kendi uygulamalarını sağlayabilir.

İlk olarak, yönteminin gövdesi dahil olmak üzere arabirimine yeni yöntemi ekleyin:

// Version 1:
public decimal ComputeLoyaltyDiscount()
{
    DateTime TwoYearsAgo = DateTime.Now.AddYears(-2);
    if ((DateJoined < TwoYearsAgo) && (PreviousOrders.Count() > 10))
    {
        return 0.10m;
    }
    return 0;
}

Kitaplık yazarı uygulamayı denetlemek için ilk testi yazdı:

SampleCustomer c = new SampleCustomer("customer one", new DateTime(2010, 5, 31))
{
    Reminders =
    {
        { new DateTime(2010, 08, 12), "childs's birthday" },
        { new DateTime(1012, 11, 15), "anniversary" }
    }
};

SampleOrder o = new SampleOrder(new DateTime(2012, 6, 1), 5m);
c.AddOrder(o);

o = new SampleOrder(new DateTime(2103, 7, 4), 25m);
c.AddOrder(o);

// Check the discount:
ICustomer theCustomer = c;
Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}");

Testin aşağıdaki bölümüne dikkat edin:

// Check the discount:
ICustomer theCustomer = c;
Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}");

öğesinin SampleCustomerICustomer ataması gereklidir. sınıfının SampleCustomer için arabirimi tarafından ICustomer sağlanan bir uygulama ComputeLoyaltyDiscountsağlaması gerekmez. Ancak sınıfı, SampleCustomer arabirimlerinden üyeleri devralamaz. Bu kural değişmedi. Arabirimde bildirilen ve uygulanan herhangi bir yöntemi çağırmak için değişkeni, bu örnekte arabirimin ICustomer türü olmalıdır.

Parametreleştirme sağlama

Varsayılan uygulama çok kısıtlayıcıdır. Bu sistemin birçok tüketicisi satın alma sayısı, farklı üyelik uzunluğu veya farklı bir yüzde indirimi için farklı eşikler seçebilir. Bu parametreleri ayarlamanın bir yolunu sağlayarak daha fazla müşteri için daha iyi bir yükseltme deneyimi sağlayabilirsiniz. Şimdi varsayılan uygulamayı denetleyen bu üç parametreyi ayarlayan statik bir yöntem ekleyelim:

// Version 2:
public static void SetLoyaltyThresholds(
    TimeSpan ago,
    int minimumOrders = 10,
    decimal percentageDiscount = 0.10m)
{
    length = ago;
    orderCount = minimumOrders;
    discountPercent = percentageDiscount;
}
private static TimeSpan length = new TimeSpan(365 * 2, 0,0,0); // two years
private static int orderCount = 10;
private static decimal discountPercent = 0.10m;

public decimal ComputeLoyaltyDiscount()
{
    DateTime start = DateTime.Now - length;

    if ((DateJoined < start) && (PreviousOrders.Count() > orderCount))
    {
        return discountPercent;
    }
    return 0;
}

Bu küçük kod parçasında gösterilen birçok yeni dil özelliği vardır. Arabirimler artık alanlar ve yöntemler de dahil olmak üzere statik üyeler içerebilir. Farklı erişim değiştiricileri de etkinleştirilir. Diğer alanlar özeldir, yeni yöntem geneldir. Değiştiricilerden herhangi birine arabirim üyelerinde izin verilir.

Bağlılık programı indirimini hesaplamaya yönelik genel formülü kullanan ancak farklı parametreler kullanan uygulamaların özel bir uygulama sağlaması gerekmez; bağımsız değişkenleri statik bir yöntemle ayarlayabilirler. Örneğin, aşağıdaki kod bir aydan fazla üyelikle tüm müşterileri ödüllendiren bir "müşteri takdiri" ayarlar:

ICustomer.SetLoyaltyThresholds(new TimeSpan(30, 0, 0, 0), 1, 0.25m);
Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}");

Varsayılan uygulamayı genişletme

Şimdiye kadar eklediğiniz kod, kullanıcıların varsayılan uygulama gibi bir şey istediği veya ilgisiz bir kural kümesi sağladığı senaryolar için kullanışlı bir uygulama sağladı. Son bir özellik için, kullanıcıların varsayılan uygulama üzerinde derleme yapmak isteyebileceği senaryoları etkinleştirmek için kodu biraz yeniden düzenleyelim.

Yeni müşterileri çekmek isteyen bir başlangıç düşünün. Yeni bir müşterinin ilk siparişi için %50 indirim sunarlar. Aksi takdirde, mevcut müşteriler standart indirimi alır. Kitaplık yazarının, bu arabirimi uygulayan herhangi bir sınıfın kodu kendi uygulamalarında yeniden kullanabilmesi için varsayılan uygulamayı bir protected static yönteme taşıması gerekir. Arabirim üyesinin varsayılan uygulaması bu paylaşılan yöntemi de çağırır:

public decimal ComputeLoyaltyDiscount() => DefaultLoyaltyDiscount(this);
protected static decimal DefaultLoyaltyDiscount(ICustomer c)
{
    DateTime start = DateTime.Now - length;

    if ((c.DateJoined < start) && (c.PreviousOrders.Count() > orderCount))
    {
        return discountPercent;
    }
    return 0;
}

Bu arabirimi uygulayan bir sınıfın uygulamasında geçersiz kılma statik yardımcı yöntemini çağırabilir ve "yeni müşteri" indirimi sağlamak için bu mantığı genişletebilir:

public decimal ComputeLoyaltyDiscount()
{
   if (PreviousOrders.Any() == false)
        return 0.50m;
    else
        return ICustomer.DefaultLoyaltyDiscount(this);
}

Tamamlanmış kodun tamamını GitHub'daki örnek depomuzda görebilirsiniz. Başlangıç uygulamasını GitHub'da bulunan örnek depomuzdan alabilirsiniz.

Bu yeni özellikler, bu yeni üyeler için makul bir varsayılan uygulama olduğunda arabirimlerin güvenli bir şekilde güncelleştirilebileceği anlamına gelir. Birden çok sınıf tarafından uygulanan tek işlevsel fikirleri ifade etmek için arabirimleri dikkatlice tasarlar. Bu, aynı işlevsel fikir için yeni gereksinimler bulunduğunda bu arabirim tanımlarını yükseltmeyi kolaylaştırır.