JavaRush /Java Blog /Random-ID /Pola Desain “Strategi”

Pola Desain “Strategi”

Dipublikasikan di grup Random-ID
Halo! Pada perkuliahan sebelumnya kita telah menjumpai konsep “pola desain”. Jika Anda lupa, izinkan kami mengingatkan Anda: istilah ini menunjukkan solusi standar tertentu untuk masalah umum dalam pemrograman. Pola desain "Strategi" - 1Di JavaRush kami sering mengatakan bahwa jawaban atas hampir semua pertanyaan dapat dicari di Google. Oleh karena itu, seseorang mungkin telah berhasil memecahkan masalah serupa dengan Anda. Jadi, pola adalah solusi yang telah teruji waktu dan teruji praktik untuk masalah atau metode paling umum untuk menyelesaikan situasi masalah. Ini adalah "sepeda" yang sama yang tidak perlu Anda ciptakan sendiri, tetapi Anda perlu tahu bagaimana dan kapan menerapkannya :) Tugas pola lainnya adalah membawa arsitektur ke standar tunggal. Membaca kode orang lain bukanlah tugas yang mudah! Setiap orang menulisnya berbeda-beda, karena masalah yang sama dapat diselesaikan dengan banyak cara. Namun penggunaan pola memungkinkan pemrogram yang berbeda untuk memahami logika program tanpa mempelajari setiap baris kode (bahkan jika mereka melihatnya untuk pertama kali!) Hari ini kita akan melihat salah satu pola paling umum yang disebut “Strategi”. Pola desain "Strategi" - 2Bayangkan kita sedang menulis sebuah program yang secara aktif bekerja dengan objek Car. Dalam hal ini, apa sebenarnya yang dilakukan program kami tidak terlalu penting. Untuk melakukan hal ini, kami membuat sistem pewarisan dengan satu kelas induk Autodan tiga kelas anak: Sedan, Truckdan F1Car.
public class Auto {

   public void gas() {
       System.out.println("Едем вперед");
   }

   public void stop() {

       System.out.println("Тормозим!");
   }
}

public class Sedan extends Auto {
}

public class Truck extends Auto {
}

public class F1Car extends Auto {
}
Ketiga kelas anak mewarisi dua metode standar dari induknya - gas()dan stop() program kami sepenuhnya sederhana: mobil hanya dapat melaju dan mengerem. Melanjutkan pekerjaan kami, kami memutuskan untuk menambahkan metode baru pada mobil - fill()(mengisi bahan bakar). Mari kita tambahkan ke kelas induk Auto:
public class Auto {

   public void gas() {
       System.out.println("Едем вперед");
   }

   public void stop() {

       System.out.println("Тормозим!");
   }

   public void fill() {
       System.out.println("Заправить бензин!");
   }
}
Tampaknya, masalah bisa muncul dalam situasi sederhana seperti itu? Sebenarnya, mereka sudah muncul... Pola Desain “Strategi” - 3
public class ChildrenBuggies extends Auto {

   public void fill() {

       //хм... Это детский багги, его не надо заправлять :/
   }
}
Sebuah mobil telah muncul di program kami yang tidak sesuai dengan konsep umum - kereta anak-anak. Ini mungkin bertenaga pedal atau dikendalikan radio, tapi satu hal yang pasti - tidak ada tempat untuk memasukkan bensin ke dalamnya. Skema pewarisan kami mengakibatkan kami memberikan metode umum bahkan kepada kelas yang tidak membutuhkannya. Apa yang harus kita lakukan dalam situasi seperti ini? Misalnya, Anda dapat mengganti metode fill()di kelas ChildrenBuggiessehingga ketika Anda mencoba mengisi bahan bakar kereta, tidak terjadi apa-apa:
public class ChildrenBuggies extends Auto {

   @Override
   public void fill() {
       System.out.println("Игрушечную машину нельзя заправить!");
   }
}
Namun solusi ini sulit disebut berhasil, setidaknya karena duplikasi kode. Misalnya, sebagian besar kelas akan menggunakan metode dari kelas induk, namun kelas lain akan terpaksa menggantinya. Jika kita memiliki 15 kelas, dan di kelas 5-6 kita dipaksa untuk mengganti perilaku, duplikasi kode akan menjadi cukup luas. Mungkin antarmuka dapat membantu kita? Misalnya yang ini:
public interface Fillable {

   public void fill();
}
Kami akan membuat antarmuka Fillabledengan satu metode fill(). Oleh karena itu, mobil-mobil yang perlu mengisi bahan bakar akan menerapkan antarmuka ini, tetapi mobil lain (misalnya, kereta kami) tidak. Tapi opsi ini juga tidak cocok untuk kita. Hirarki kelas kita mungkin akan bertambah menjadi jumlah yang sangat besar di masa depan (bayangkan berapa banyak jenis mobil yang ada di dunia). Kami mengabaikan opsi pewarisan sebelumnya karena kami tidak ingin mengganti opsi warisan fill(). Di sini kita harus menerapkannya di setiap kelas! Bagaimana jika kita punya 50 buah? Dan jika perubahan sering dilakukan pada program kita (dan dalam program nyata hal ini hampir selalu terjadi!), Kita harus berjalan-jalan di antara 50 kelas dan mengubah perilaku masing-masing kelas secara manual. Jadi apa yang harus kita lakukan pada akhirnya? Untuk mengatasi masalah kita, mari kita memilih jalan yang berbeda. Yaitu, mari kita pisahkan perilaku kelas kita dari kelas itu sendiri. Apa artinya? Seperti yang Anda ketahui, objek apa pun memiliki status (sekumpulan data) dan perilaku (sekumpulan metode). Perilaku kelas mesin kami terdiri dari tiga metode - gas(), stop()dan fill(). Dua metode pertama baik-baik saja. Tapi kami akan memindahkan metode ketiga ke luar kelas Auto. Ini akan menjadi pemisahan perilaku dari kelas (lebih tepatnya, kita hanya memisahkan sebagian dari perilaku - dua metode pertama tetap ada). Ke mana kita harus memindahkan metode kita fill()? Tidak ada yang terlintas dalam pikiran :/ Dia sepertinya benar-benar berada di tempatnya. Kami akan memindahkannya ke antarmuka terpisah - FillStrategy!
public interface FillStrategy {

   public void fill();
}
Mengapa kita memerlukan antarmuka ini? Itu mudah. Sekarang kita dapat membuat beberapa kelas yang akan mengimplementasikan antarmuka ini:
public class HybridFillStrategy implements FillStrategy {

   @Override
   public void fill() {
       System.out.println("Заправляем бензином or электричеством на выбор!");
   }
}

public class F1PitstopStrategy implements FillStrategy {

   @Override
   public void fill() {
       System.out.println("Заправляем бензин только после всех остальных procedures пит-стопа!");
   }
}

public class StandartFillStrategy implements FillStrategy {
   @Override
   public void fill() {
       System.out.println("Просто заправляем бензин!");
   }
}
Kami telah menciptakan tiga strategi perilaku - untuk mobil konvensional, untuk mobil hibrida, dan untuk mobil Formula 1. Setiap strategi menerapkan algoritma pengisian bahan bakar terpisah. Dalam kasus kami, ini hanyalah keluaran ke konsol, tetapi mungkin ada logika kompleks di dalam metode ini. Apa yang harus kita lakukan selanjutnya?
public class Auto {

   FillStrategy fillStrategy;

   public void fill() {
       fillStrategy.fill();
   }

   public void gas() {
       System.out.println("Едем вперед");
   }

   public void stop() {
       System.out.println("Тормозим!");
   }

}
Kami menggunakan antarmuka kami FillStrategysebagai bidang di kelas induk Auto. Harap diperhatikan: kami tidak menentukan implementasi spesifik, melainkan menggunakan antarmuka. Dan kita memerlukan implementasi antarmuka yang spesifik FillStrategydi kelas mobil anak:
public class F1Car extends Auto {

   public F1Car() {
       this.fillStrategy = new F1PitstopStrategy();
   }
}

public class HybridAuto extends Auto {

   public HybridAuto() {
       this.fillStrategy = new HybridFillStrategy();
   }
}

public class Sedan extends Auto {

   public Sedan() {
       this.fillStrategy = new StandartFillStrategy();
   }
}
Mari kita lihat apa yang kita dapatkan:
public class Main {

   public static void main(String[] args) {

       Auto sedan = new Sedan();
       Auto hybrid = new HybridAuto();
       Auto f1car = new F1Car();

       sedan.fill();
       hybrid.fill();
       f1car.fill();
   }
}
Keluaran konsol:

Просто заправляем бензин!
Заправляем бензином or электричеством на выбор!
Заправляем бензин только после всех остальных procedures пит-стопа!
Hebat, proses pengisian bahan bakar berjalan sebagaimana mestinya! Omong-omong, tidak ada yang menghalangi kita untuk menggunakan strategi sebagai parameter di konstruktor! Misalnya seperti ini:
public class Auto {

   private FillStrategy fillStrategy;

   public Auto(FillStrategy fillStrategy) {
       this.fillStrategy = fillStrategy;
   }

   public void fill() {
       this.fillStrategy.fill();
   }

   public void gas() {
       System.out.println("Едем вперед");
   }

   public void stop() {
       System.out.println("Тормозим!");
   }
}

public class Sedan extends Auto {

   public Sedan() {
       super(new StandartFillStrategy());
   }
}



public class HybridAuto extends Auto {

   public HybridAuto() {
       super(new HybridFillStrategy());
   }
}

public class F1Car extends Auto {

   public F1Car() {
       super(new F1PitstopStrategy());
   }
}
Mari jalankan metode kita main()(tetap tidak berubah) dan dapatkan hasil yang sama! Keluaran konsol:

Просто заправляем бензин!
Заправляем бензином or электричеством на выбор!
Заправляем бензин только после всех остальных procedures пит-стопа!
Pola Strategi mendefinisikan sekumpulan algoritme, merangkum masing-masing algoritme, dan memastikan bahwa algoritme tersebut dapat dipertukarkan. Ini memungkinkan Anda untuk memodifikasi algoritme terlepas dari penggunaannya di sisi klien (definisi ini diambil dari buku "Menjelajahi Pola Desain" dan menurut saya sangat berhasil). Pola Desain “Strategi” - 4Kami telah mengisolasi rangkaian algoritme yang kami minati (jenis mobil pengisian bahan bakar) ke dalam antarmuka terpisah dengan beberapa implementasi. Kami telah memisahkannya dari esensi mobil. Oleh karena itu, sekarang, jika kita perlu melakukan perubahan apa pun pada proses pengisian bahan bakar ini atau itu, hal ini tidak akan mempengaruhi kelas mobil kita dengan cara apa pun. Sedangkan untuk pertukaran, untuk mencapainya kita hanya perlu menambahkan satu metode penyetel ke kelas kita Auto:
public class Auto {

   FillStrategy fillStrategy;

   public void fill() {
       fillStrategy.fill();
   }

   public void gas() {
       System.out.println("Едем вперед");
   }

   public void stop() {
       System.out.println("Тормозим!");
   }

   public void setFillStrategy(FillStrategy fillStrategy) {
       this.fillStrategy = fillStrategy;
   }
}
Sekarang kita dapat mengubah strategi dengan cepat:
public class Main {

   public static void main(String[] args) {

       ChildrenBuggies buggies = new ChildrenBuggies();
       buggies.setFillStrategy(new StandartFillStrategy());

       buggies.fill();
   }
}
Jika tiba-tiba mobil buggy anak-anak mulai diisi bensin, program kami akan siap untuk skenario seperti itu :) Sebenarnya itu saja! Anda telah mempelajari pola desain lain, yang pasti Anda perlukan dan akan membantu Anda lebih dari sekali saat mengerjakan proyek nyata :) Sampai jumpa lagi!
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION