Menggunakan Kotoran dalam Aplikasi Flutter



Saya bekerja di perusahaan pengembang game, tetapi sebagai hobi rumahan, saya baru-baru ini tertarik untuk mengembangkan aplikasi mobile. Karena itu, ketika seorang teman mengundang saya ke pertemuan yang didedikasikan untuk pengembangan aplikasi seluler menggunakan kerangka kerja Flutter, saya setuju dengan senang hati. Setelah mencoba Flutter beraksi di sana, saya memutuskan untuk mempelajari teknologi ini dengan pasti. Karena Dart yang dibutuhkan untuk pengembangan tidak asing bagi saya, pembelajaran bahasa juga termasuk dalam program wajib. Setelah duduk sedikit di atas contoh kode, saya menemukan Dart bahasa yang mudah dimengerti dan ringkas yang sangat saya sukai. Salah satu fitur Dart yang saya sukai adalah kotoran.

Apa itu pengotor?


Untuk seorang kenalan awal, saya akan memberikan kutipan dari Wikipedia .
Admixture (campuran Bahasa Inggris) adalah elemen dari bahasa pemrograman (biasanya kelas atau modul) yang mengimplementasikan beberapa perilaku yang jelas. Digunakan untuk memperjelas perilaku kelas lain, tidak dimaksudkan untuk menghasilkan objek yang digunakan secara independen.
Di Dart, konstruksi seperti itu didefinisikan oleh kata mixin sebelum nama.

Definisi di atas berarti bahwa kita mendapatkan fungsionalitas perilaku yang terisolasi secara logis yang dapat ditambahkan ke kelas lain.

Apakah itu mengingatkan Anda tentang kemungkinan pewarisan berganda? Ya, tetapi bagi saya tampaknya pendekatan pengotor lebih baik. Dan mengapa, mari kita lihat sebuah contoh.

Misalkan kita memiliki kelas hewan abstrak.

abstract class Animal { void voice(); } 

Dan juga kelas Kucing dan Anjing yang mengimplementasikan kelas Hewan.

 class Cat extends Animal { void voice() { print(“Meow”); } } class Dog extends Animal { void voice() { print(“Woof”); } } 

Dan kemudian kami tiba-tiba membutuhkan ...
kucing

Ya, ya, saya pribadi tidak memiliki hal seperti itu selama pengembangan.

Dan dalam hal pewarisan berganda, kami akan melakukan hal yang sama.

 class CatDog extends Cat, Dog { } 

Tetapi segera setelah kami menyuarakan perintah suara kami kepada hewan peliharaan kami, kami mendapatkan situasi yang sangat tidak menyenangkan - tidak jelas apa tepatnya yang harus ia jawab, karena metode suara diterapkan di kedua kelas. Keadaan ini dikenal luas dan disebut masalah berlian atau Deadly Diamond of Death .

Berlian kematian yang mematikan

Dalam hal penjualan melalui pengotor, kami tidak akan menjumpainya.

 lass Animal { void voice() { print(“Hakuna Matata!”); } } mixin Cat { void voice() { print(“Meow”); } } mixin Dog { void voice() { print(“Woof”); } } class CatDog extends Animal with Cat, Dog { } 

Dan apa yang akan kita dengar jika sekarang kita memberikan perintah suara? Dalam hal ini - Pakan, dan seperti yang Anda sudah mengerti, itu tergantung pada urutan penambahan kotoran. Ini terjadi karena penambahan mereka tidak paralel, tetapi berurutan.

Saya mengimplementasikan kelas Animal secara khusus untuk menandai fitur yang diperkenalkan di Dart 2.1 . Sebelumnya, pengotor hanya bisa ditambahkan ke kelas yang diwarisi dari Object . Dimulai dengan versi 2.1, penambahan setiap kelas ke ahli waris diimplementasikan.

Mekanisme ini membuatnya sangat mudah untuk membuat dan menggunakan bagian umum dari fungsional, yang memecahkan masalah duplikasi kode. Mari kita lihat sebuah contoh.

 abstract class Sportsman { void readySteadyGo(); } mixin SkiRunner { void run() { print(“Ski, ski, ski”); } } mixin RifleShooter { void shot() { print(“Pew, pew, pew”); } } class Shooter() extends Sportsman with RifleShooter { void readySteadyGo() { shot(); } } class Skier() extends Sportsman with SkiRunner { void readySteadyGo() { run(); } } class Biathlete() extends Sportsman with SkiRunner, RifleShooter { void readySteadyGo() { run(); shot(); } } 

Seperti yang Anda lihat, kami mendistribusikan semua kode duplikat oleh kotoran dan hanya menggunakan yang diperlukan di setiap implementasi.

Selama pengembangan, suatu situasi dapat muncul ketika fungsi dari salah satu pengotor tidak boleh tersedia untuk umum untuk dimasukkan oleh semua kelas. Dan mekanisme yang akan memungkinkan kita untuk menerapkan pembatasan ini juga tersedia. Ini adalah kata kunci on pada deklarasi pencampuran bersama dengan nama kelas. Jadi kami akan membatasi penggunaan pengotor hanya untuk kelas yang mengimplementasikan yang ditentukan atau diwarisi darinya.

Sebagai contoh:

 class A { } abstract class B { } mixin M1 on A { } mixin M2 on B { } 

Kemudian kita dapat mendeklarasikan kelas yang serupa:

 class C extends A with M1 { } class D implements B with M2 { } 

Tetapi kami mendapatkan kesalahan saat mencoba menyatakan sesuatu seperti ini:
 class E with M1, M2 { } 

Penggunaan dalam Aplikasi Flutter


Seperti yang saya sebutkan di atas, pengotor memungkinkan Anda untuk menyingkirkan duplikasi kode dan membuat bagian-bagian logis terpisah yang dapat digunakan kembali. Tapi bagaimana ini berlaku untuk Flutter, di mana semuanya atom dan dibagi menjadi widget yang bertanggung jawab untuk fungsi tertentu? Sebagai contoh, saya langsung membayangkan situasi di mana proyek menggunakan banyak widget, tampilan yang bervariasi tergantung pada keadaan internal tertentu. Saya akan mempertimbangkan contoh ini dalam arsitektur BLoC dan menggunakan entitas dari perpustakaan rxDart.

Kami membutuhkan antarmuka untuk menutup pengontrol aliran.

 /// Interface for disposable objects abstract class Disposable { void dispose(); } 

Campuran dengan mana kami menerapkan dukungan negara.

 /// Mixin for object which support state mixin StateProvider implements Disposable { static const NONE_STATE = "None"; final _stateController = BehaviorSubject<String>(seedValue: NONE_STATE); Observable<String> get stateOut => _stateController.stream; String get currentState => _stateController.value; void setState(String state) { _stateController.sink.add(state); } @override void dispose() { _stateController.close(); } } 

Bagian logis yang akan mengontrol keadaan widget. Biarkan dia mengatur negara dengan memanggil metode dan setelah 3 detik mengubahnya ke yang lain.

 /// Example BLoC class ExampleBloc implements Disposable with StateProvider { static const EXAMPLE_STATE_1 = "EX1"; static const EXAMPLE_STATE_2 = "EX2"; Timer _timer; void init() { setState(EXAMPLE_STATE_1); _timer = new Timer(const Duration(seconds: 3), () { _timer = null; setState(EXAMPLE_STATE_2); }); } @override void dispose() { if (_timer != null) { _timer.cancel(); _timer = null; } } } 

Dan widget itu sendiri yang akan merespons perubahan status. Bayangkan mendapatkan komponen logis yang diinginkan menggunakan Dependency Injection.

 class ExampleWidget extends StatelessWidget { final bloc = di<HomePageBloc>(); @override Widget build(BuildContext context) { return StreamBuilder( stream: bloc.stateOut, builder: (BuildContext context, AsyncSnapshot<String> snapshot) { // build widget by state }, ); } } 

Jika diinginkan, kita bahkan dapat menambahkan ke campuran apa yang tertulis dan hanya memerlukan implementasi metode pembangun menggunakan antarmuka, tetapi bagi saya sepertinya ini sudah tidak perlu, karena tidak mungkin bahwa akan ada banyak widget sederhana dalam proyek, karena itu hanya sebuah contoh. Namun demikian, bagian logis dari fungsional dukungan negara akan dengan mudah ditambahkan ke salah satu BLoC menggunakan pencampuran ini.

Kesimpulan


Bagi saya, mekanisme menggunakan kotoran adalah alat pengembangan yang agak menarik dan fleksibel, yang memungkinkan untuk membangun arsitektur yang sederhana, mudah dimengerti, dan nyaman. Bagi saya sendiri, saya memutuskan bahwa alat ini dalam kit saya jelas tidak akan berlebihan, saya berharap itu akan bermanfaat bagi Anda juga.

Sumber:
Tur bahasa panah
Wikipedia

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


All Articles