Lebih Baik Memahami Pola Desain 'Strategi'

8

Saya telah tertarik pada pola desain untuk sementara waktu dan mulai membaca "Pola Desain Kepala Pertama". Saya mulai dengan pola pertama yang disebut pola 'Strategi'. Saya membahas masalah yang diuraikan dalam gambar di bawah ini dan pertama kali mencoba mengusulkan solusi sendiri sehingga saya benar-benar dapat memahami pentingnya pola.

Jadi pertanyaan saya adalah mengapa solusi saya untuk masalah di bawah ini tidak cukup baik. Apa poin baik / buruk dari solusi saya vs polanya? Apa yang membuat pola itu jelas satu-satunya solusi yang bisa dilakukan?

SOLUSI SAYA

Kelas Induk: DUCK

<?php
class Duck
{
 public  $swimmable;
 public  $quackable;
 public  $flyable;

 function display()
 {
  echo "A Duck Looks Like This<BR/>";
 }

 function  quack()
 {
  if($this->quackable==1)
  {
   echo("Quack<BR/>");
  }
 }

 function swim()
 {
  if($this->swimmable==1)
  {
   echo("Swim<BR/>");
  }
 }

 function  fly()
 {
  if($this->flyable==1)
  {
   echo("Fly<BR/>");
  }
 }


}
?>

KELAS INHERIT: MallardDuck

<?php
class MallardDuck extends Duck
{
 function MallardDuck()
 {
  $this->quackable = 1;
  $this->swimmable = 1;
 }

 function display()
 {
  echo "A Mallard Duck Looks Like This<BR/>";
 }
}
?>

KELAS Warisan: WoddenDecoyDuck

<?php
class WoddenDecoyDuck extends Duck
{
 function woddendecoyduck()
 {
  $this->quackable = 0;
  $this->swimmable = 0;
 }

 function display()
 {
  echo "A Wooden Decoy Duck Looks Like This<BR/>";
 }
}
Imran Omar Bukhsh
sumber
solusi Anda tidak persis apa yang dimaksud (atau bahkan solusi untuk yang) pada buku
mauris
dapatkah Anda membantu menjelaskan dengan lebih baik
Imran Omar Bukhsh
5
Saya tidak yakin bahwa Anda dapat memindai halaman dari pola Desain Kepala Pertama dan hanya meletakkannya di web.
Ladislav Mrnka
1
Ini terlihat seperti Peninjauan Kode .
Steven Jeuris
2
@Imran Sebagaimana disebutkan di Amazon, halaman-halaman itu adalah materi yang dilindungi hak cipta. Mereka tidak dapat diposkan secara bebas di sini. Harap edit pertanyaan untuk menyatakan masalah dengan kata-kata Anda sendiri.
Adam Lear

Jawaban:

6

Kode Anda akan pecah ketika, misalnya bebek dukun dengan suara yang berbeda. Boolean hanya akan menyebabkan boolean lain menjadi pernyataan if yang sangat berbulu.

Namun, pola strateginya sederhana. Ambil contoh ini metode quack dan letakkan di kelas atau antarmuka itu sendiri. Antarmuka di php akan menjadi kelas yang tidak mengandung implementasi apa pun selain metode yang bertopik (yaitu tidak ada yang terjadi ketika Anda memanggilnya).

class Quackable {
    function quack() {}
}

Dengan begitu Anda dapat membuat beberapa implementasi quackable:

class DuckQuack extends Quackable {
    function quack() {
        return "Quack!";
    }
}

class SilentQuack extends Quackable {
    function quack() {
        return ""; 
            // The decoy duck can't quack. It is silent.
    }
}

Dan karena kami melakukannya dengan bijaksana, kami dapat menambahkan lebih banyak jenis "perdukunan":

class DoubleQuack extends Quackable {
    function quack() {
        return "Quackety-quack!"
    }
}

Hal yang sama dapat diterapkan untuk metode terbang dan berenang untuk kelas Bebek. Cara Anda mengimplementasikan kelas Duck dengan quackable akan seperti ini (antarmuka quackable disediakan melalui konstruktor, yang merupakan semacam cara kerja ketergantungan injeksi):

class Duck {
    protected $quackable;

    // The constructor
    function __construct($quackable) {
        $this->quackable = quackable;
    }

    function quack() {
        echo $this->quackable->quack();
    }
}

Menerapkan bebek mallard dan bebek umpan akan mudah karena Anda hanya perlu menyediakan jenis dukun apa yang harus dilakukan bebek:

class MallardDuck extends Duck {
    function __construct() {
        parent::__construct(new DuckQuack());
           // we construct the mallard duck with a duck quack
    }
}

class DecoyDuck extends Duck {
    function __construct() {
        parent::__construct(new SilentQuack());
           // we construct the decoy duck with a silent quack
    }
}

Menggunakan itu semua sederhana:

$duck1 = new MallardDuck();
$duck2 = new DecoyDuck();

$duck1.quack(); // echoes out "Quack!"
$duck2.quack(); // echoes out "" (because decoy ducks don't quack)

Saya harap ini semua masuk akal bagi Anda.

Spoike
sumber
Kode mungkin memiliki kesalahan, sudah lama sejak saya kode sesuatu di php. :-P
Spoike
Selain itu, OP perlu membalik beberapa halaman lagi untuk mendapatkan pola Strategi dan prinsip "komposisi sebelum warisan" dalam buku itu. :) Halaman yang dipindai diawali dengan masalah warisan.
Spoike
thanx untuk penjelasannya
Imran Omar Bukhsh
4

Pertama-tama, masalah Anda tidak ada hubungannya dengan pola strategi. Ide dari pola strategi adalah faktor tanggung jawab untuk perilaku tertentu ke dalam kelas yang berbeda. Dengan begitu, Anda bisa mencolokkan perilaku yang berbeda menjadi satu instance pada saat run time.

Sekarang solusi Anda bekerja dengan cukup baik untuk skenario yang Anda masuki, tetapi skenario itu hanya latihan, yang cukup jauh dari masalah dunia nyata.
Jika Anda menggunakan teknik ini untuk menangani proyek-proyek besar, Anda berisiko berakhir dengan 5-10 lapisan warisan, di mana setiap subkelas digabungkan ke semakin banyak bendera. Kode seperti itu sangat rapuh dan verbal. Mengotak-atik keadaan internal semua kelas super bukanlah cara OOP menangani hal-hal seperti itu, karena mengaburkan pemisahan masalah.

Solusi menggunakan antarmuka secara signifikan lebih bersih, lebih kuat dan dengan demikian akan terbukti lebih dapat dipertahankan dari waktu ke waktu. Cobalah untuk tidak membuat bebek pangkalan serba guna umum, tetapi membuat abstraksi yang jelas tentang berbagai aspek bebek yang berbeda. Saya baru saja membuat posting blog tentang hal ini, Anda mungkin menemukan bermanfaat.

back2dos
sumber
1
+1 tetapi saya harus mengatakan, bahwa ini adalah contoh yang diberikan untuk Pola Strategi dalam buku, yang merupakan buku yang sangat bagus. Sayangnya dia belum menunjukkan halaman berikutnya di mana perilaku terbang, dukun dll dirancang dan kemudian dicolokkan ke bebek (yaitu bagian yang menerapkan pola strategi untuk masalah), tetapi itu ada di buku.
Alb
Saya telah menambahkan halaman buku berikutnya untuk menunjukkan mengapa solusi antarmuka total tidak, tidak, tidak!
Imran Omar Bukhsh
@Alb: ya sekitar 13 halaman
Imran Omar Bukhsh
@Imran: Maaf, tapi penulis buku ini jelas-jelas salah. Antarmuka tidak mengatakan apa - apa tentang implementasi. Kelas dapat diimplementasikan melalui komposisi atau delegasi (pola strategi menjadi kasus khusus). Namun, memberikan metode terbang pada bebek yang tidak bisa terbang, hanya karena Anda tidak bisa menyelesaikannya, sebaliknya desain yang buruk. Dan itu tidak skala. Bagaimana jika Anda juga memilikinya RuberBall? Akankah RuberDuckjuga memiliki metode roll kosong?
back2dos
3

Ah, pertanyaan bagus. Saya tidak berpikir itu adalah praktik yang sangat baik untuk memiliki variabel anggota yang mengubah fungsi. Terutama masalah dengan solusi ini adalah bahwa karena Anda mengekspos flydan quackmetode di Duckkelas itu akan tampak bahwa Anda mengatakan bahwa "Semua bebek bisa fly/ quack." Apa yang lebih buruk adalah itu, tergantung pada jenis runtime dari contoh bebek yang saya miliki, flyatau quackmungkin atau mungkin tidak melakukan apa-apa. Ini dapat menyebabkan kode yang sangat membingungkan.

Sedangkan, dalam contoh yang diberikan buku, saat Anda mengharapkan bebek yang bisa terbang, Anda bisa mengetik (atau menguji, karena Anda menggunakan bahasa dinamis) jika itu Flyablebebek.

Jika setiap kali saya memiliki bebek, sebelum saya memanggilnya quacksaya harus memutuskan harus memeriksa apakah variabel anggota yang dapat diterbangkan diatur ke true yang akan menyebabkan banyak duplikasi kode.

if($duck->quackable) $duck->quack();

The Flyableantarmuka membantu membangun harapan. Ya, quackmetode default Anda akan memeriksa apakah seharusnya atau tidak, tetapi saya, sebagai penelepon, tidak memiliki jaminan bahwa itu bahkan aman untuk dipanggil quack. Juga pikirkan skenario dengan RubberDuckyyang harus mencicit daripada dukun. Ketika Anda mengganti quackmetode Anda harus tahu untuk memeriksa $quackablevariabel anggota sebelum Anda mengambil tindakan apa pun.

Hal lain yang saya pikir membuat solusi ini tidak jelas adalah karena Anda menggunakan bahasa dinamis seperti PHP, itu membuat pengaturan ekspektasi tentang tipe input menjadi sulit. (Bukan berarti ada yang salah dengan ini, tetapi bahasa yang diketik secara statis mungkin membuatnya lebih mudah untuk dipahami.)

Saya harap ini membantu dan masuk akal.

Sandi
sumber
1

Kode Anda akan menjadi berantakan dengan cepat jika Anda telah mengatakan 10 jenis bebek yang berbeda yang semuanya memiliki kombinasi berbeda dari 3 varian terbang, dukun, dan berenang.

Secara pribadi, saya menemukan bahwa nilai sebenarnya dari pola strategi menjadi jelas ketika saya mulai menulis tes unit dan menggunakan injeksi ketergantungan. Jika Anda tidak menggunakannya, Anda akan mengalami banyak masalah dalam mengelola dependensi dan karenanya membuat objek dalam pengujian Anda.

Anda akan sampai pada situasi di mana membuat bebek menjadi rumit, maka Anda mungkin ingin menulis unit test untuk beberapa metode quacking atau terbang, tetapi Anda tidak dapat melakukannya tanpa membuat bebek dalam tes Anda.

Alb
sumber
1

Memiliki keadaan boolean untuk menyimpan apakah bebek dapat dukun / terbang, adalah solusi yang sangat spesifik untuk masalah khusus yang Anda hadapi dalam desain kelas Anda dan mungkin tidak berlaku untuk kasus-kasus lain di mana pola strategi sesuai.

Saya pikir pendekatan 'quackable' Anda membuat kode sedikit lebih berbelit-belit. Ini satu hal lagi yang Anda, dan pengguna kelas Anda harus waspada daripada yang diperlukan jika Anda menggunakan pola strategi.

Akhirnya, karena kode sampel Anda tidak menunjukkan contoh bagaimana Anda akan mengganti metode 'dukun' dan 'terbang', Anda tidak memperhatikan manfaat besar menggunakan pola strategi - mengurangi duplikasi kode. Apa yang akan Anda lakukan dengan memberikan selusin kelas bebek berbeda yang di antara mereka memiliki 3 perilaku 'terbang' yang berbeda? Dengan menggunakan pendekatan Anda, Anda mungkin menemukan diri Anda memotong dan menempel, dan kemudian mungkin mengekstrak kode duplikat ke dalam kelas 'pembantu' statis. Pola strateginya jauh lebih bersih.

richeym
sumber
1

Demo visual yang bagus selalu bernilai ribuan kata.

John Lindquist melakukan pekerjaan yang baik untuk merekam screencasts tentang pola Desain yang berbeda. Anda dapat menemukan 50 sen tentang pola khusus ini (dan banyak lagi) di blognya

Pierre Watelet
sumber