Panduan: Memperbarui Antarmuka dengan Anggota Default di C # 8.0

Dimulai dengan C # 8.0 pada .NET Core 3.0, saat membuat anggota antarmuka, Anda dapat menentukan implementasinya. Skenario yang paling umum adalah menambahkan anggota secara aman ke antarmuka yang sudah dirilis dan digunakan oleh banyak klien.

Dalam panduan ini Anda akan belajar cara:


  • Aman untuk memperluas antarmuka dengan menambahkan metode dengan implementasi.
  • Buat implementasi parameter untuk fleksibilitas yang lebih besar.
  • Dapatkan hak untuk mengimplementasikan implementasi yang lebih spesifik dengan kemungkinan kontrol manual.



Di mana untuk memulai?


Pertama, Anda perlu mengkonfigurasi mesin untuk bekerja dengan .NET Core, termasuk kompiler dari pratinjau C # 8.0. Kompiler semacam itu tersedia mulai dengan Visual Studio 2019 , atau dengan SDK pratinjau .NET Core 3.0 yang lebih baru. Anggota antarmuka default tersedia mulai dengan .NET Core 3.0 (Pratinjau 4).


Ikhtisar skenario


Tutorial ini dimulai dengan versi pertama dari perpustakaan hubungan pelanggan. Anda bisa mendapatkan aplikasi starter di repositori kami di GitHub . Perusahaan yang membuat perpustakaan ini berasumsi bahwa pelanggan dengan aplikasi yang ada akan menyesuaikannya dengan perpustakaan ini. Para pengguna diberikan definisi antarmuka minimum untuk implementasi:


public interface ICustomer { IEnumerable<IOrder> PreviousOrders { get; } DateTime DateJoined { get; } DateTime? LastOrder { get; } string Name { get; } IDictionary<DateTime, string> Reminders { get; } } 

Antarmuka kedua juga ditentukan yang menunjukkan urutan:


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

Berdasarkan antarmuka ini, tim dapat membangun perpustakaan untuk penggunanya untuk menciptakan pengalaman terbaik bagi pelanggan. Tujuan tim adalah untuk meningkatkan tingkat interaksi dengan pelanggan yang sudah ada dan mengembangkan hubungan dengan yang baru.


Saatnya memperbarui perpustakaan untuk rilis berikutnya. Salah satu fitur yang paling populer adalah penambahan diskon untuk pelanggan setia yang melakukan banyak pesanan. Diskon individual baru ini diterapkan setiap kali pelanggan melakukan pemesanan. Dengan setiap implementasi ICustomer, aturan yang berbeda dapat ditetapkan untuk diskon untuk loyalitas.

Cara paling mudah untuk menambahkan fitur ini adalah memperluas antarmuka ICustomer dengan diskon apa pun. Proposal ini telah menimbulkan kekhawatiran di antara pengembang yang berpengalaman. β€œAntarmuka tidak berubah setelah rilis! Ini adalah perubahan kritis! " Di C # 8.0, implementasi antarmuka default untuk memperbarui antarmuka telah ditambahkan. Penulis perpustakaan dapat menambahkan anggota baru dan menerapkannya secara default


Implementasi default dari antarmuka memungkinkan pengembang untuk memperbarui antarmuka, sementara masih memungkinkan pengembang lain untuk menimpa implementasi ini. Pengguna perpustakaan dapat menerima implementasi default sebagai perubahan yang tidak kritis.


Perbarui menggunakan anggota antarmuka default


Tim setuju dengan implementasi standar yang paling mungkin: diskon pada loyalitas pelanggan.


Pembaruan harus berfungsi untuk menetapkan dua properti: jumlah pesanan yang diperlukan untuk menerima diskon, dan persentase diskon. Ini membuatnya menjadi skrip yang ideal untuk anggota antarmuka default. Anda dapat menambahkan metode ke antarmuka ICustomer dan memberikan implementasinya yang paling mungkin. Semua implementasi yang ada dan yang baru dapat diimplementasikan secara default atau memiliki pengaturan sendiri.


Pertama-tama tambahkan metode baru ke implementasi:


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

Penulis perpustakaan menulis tes pertama untuk memverifikasi implementasi:


 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); //  : ICustomer theCustomer = c; Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}"); 

Perhatikan bagian tes berikut:


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

Bagian ini, dari ICustomer ke ICustomer adalah penting. Kelas SampleCustomer tidak SampleCustomer menyediakan implementasi untuk ComputeLoyaltyDiscount ; ini disediakan oleh antarmuka ICustomer . Namun, kelas SampleCustomer tidak mewarisi anggota dari interface-nya. Aturan ini belum berubah. Untuk memanggil metode apa pun yang diterapkan dalam suatu antarmuka, variabel tersebut harus berupa tipe antarmuka, dalam contoh ini ICustomer .


Parameterisasi


Ini awal yang bagus. Tetapi implementasi standar terlalu terbatas. Banyak konsumen dari sistem ini dapat memilih ambang yang berbeda untuk jumlah pembelian, durasi keanggotaan yang berbeda atau diskon dalam persen yang berbeda. Anda dapat meningkatkan proses peningkatan untuk lebih banyak pelanggan dengan menyediakan cara untuk mengatur parameter ini. Mari kita tambahkan metode statis yang menetapkan tiga parameter ini yang mengontrol implementasi default:


 //  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; } 

Sepotong kode kecil ini menunjukkan banyak fitur bahasa baru. Antarmuka sekarang dapat menyertakan anggota statis, termasuk bidang dan metode. Berbagai pengubah akses juga disertakan. Bidang tambahan bersifat pribadi, dan metode baru bersifat publik. Setiap pengubah diizinkan untuk anggota antarmuka.


Aplikasi yang menggunakan rumus umum untuk menghitung diskon loyalitas, tetapi dengan parameter yang berbeda, seharusnya tidak menyediakan implementasi kustom; mereka dapat mengatur argumen dengan metode statis. Misalnya, kode berikut mengatur "apresiasi pelanggan," yang memberikan imbalan kepada pelanggan mana pun dengan keanggotaan lebih dari satu bulan:


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

Perpanjang implementasi standar


Kode yang Anda tambahkan sebelumnya memberikan implementasi yang nyaman untuk skenario di mana pengguna menginginkan sesuatu seperti implementasi default atau memberikan seperangkat aturan yang tidak terkait. Untuk versi final, mari kita mengatur ulang kode sedikit untuk memasukkan skenario di mana pengguna mungkin ingin bergantung pada implementasi default.


Pertimbangkan startup yang ingin menarik pelanggan baru. Mereka menawarkan diskon 50% untuk pesanan pertama pelanggan baru. Pelanggan yang ada menerima diskon standar. Penulis perpustakaan perlu memindahkan implementasi default ke metode protected static sehingga setiap kelas yang mengimplementasikan antarmuka ini dapat menggunakan kembali kode dalam implementasinya. Implementasi default dari anggota antarmuka juga memanggil metode umum ini:


 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; } 

Dalam implementasi kelas yang mengimplementasikan antarmuka ini, Anda dapat secara manual memanggil metode pembantu statis dan memperluas logika ini untuk memberikan diskon kepada "klien baru":


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

Anda dapat melihat semua kode yang sudah selesai di repositori kami di GitHub .


Fitur-fitur baru ini berarti bahwa antarmuka dapat diperbarui dengan aman jika ada implementasi standar yang dapat diterima untuk anggota baru. Desain antarmuka dengan hati-hati untuk mengekspresikan ide-ide fungsional individual yang dapat diimplementasikan oleh beberapa kelas. Ini membuatnya mudah untuk memperbarui definisi antarmuka ini ketika persyaratan baru ditemukan untuk ide fungsional yang sama.

Source: https://habr.com/ru/post/id456232/


All Articles