در دنیای برنامه نویسی استانداردترین کدها آن هایی هستند که دارای کمترین تکرار کد باشند. اما موقعیت هایی به وجود می آید که ما مجبور می شویم کدهای یکسان را برای انجام کارهای تقریبا یکسان با تغییرات کوچک بارها و بارها بنویسیم. در این وضعیت باید به دنبال راهکارهایی باشیم که این تکرارها را به حداقل ممکن برسانیم. برای مبارزه با این تکرارها از کلاس ها و متدهای abstract یا انتزاعی استفاده می کنیم.
خط تولید یک کارخانه دونات پزی را در نظر بگیرید. دونات ها با شیوه پخت یکسان پخته می شوند. پس از آن سس روکش مناسب با رنگ ها و طعم های مختلف مثل خامه رنگی، شکلات، قرص های رنگی و ... روی آن ها ریخته می شود. در پایان بسته به نوع سسی که روی آن ها ریخته شده بسته بندی می شوند. می بینید که همه دونات ها با هر طعم و شکلی که باشند شیوه پخت یکسانی دارند. روش نادرست این است که برای هر رنگ دونات یک خط تولید جداگانه ساخته شود. آیا این روش منطقی است؟ روش دیگر این است که خط تولید تا مرحله پخت مشترک باشد. سپس دونات ها در مرحله ریختن سس به خط تولید جداگانه دسته بندی و در پایان بسته بندی شوند. کد زیر خط تولید جداگانه دونات شکلاتی را در کلاس ChocolateDonut نمایش می دهد:
class ChocolateDonut {
public function make() {
return $this
->makeDough()
->moldDonut()
->fryDonut()
->addChocolate()
->packChocolateDonut();
}
protected function makeDough() {
print "make donut dough, first. ";
return $this;
}
protected function moldDonut() {
print "then, mold donut to have a wheel shape. ";
return $this;
}
protected function fryDonut() {
print "fry the donut carefully. ";
return $this;
}
protected function addChocolate() {
print "Add enough chocolate on the donut!";
return $this;
}
protected function packChocolateDonut() {
print "Pack donut with brown Packing! ";
return $this;
}
}
$chocolateDonut = new ChocolateDonut();
$chocolateDonut->make();
برای تهیه دونات با سس توت فرنگی نیز همین مراحل تکرار می شود:
class StrawberryDonut {
public function make() {
return $this
->makeDough()
->moldDonut()
->fryDonut()
->addStrawberrySauce()
->packStrawberryDonut();
}
protected function makeDough() {
print "make donut dough, first. ";
return $this;
}
protected function moldDonut() {
print "then, mold donut to have a wheel shape. ";
return $this;
}
protected function fryDonut() {
print "fry the donut carefully. ";
return $this;
}
protected function addStrawberrySauce() {
print "Add enough strawberry on the donut!";
return $this;
}
protected function packStrawberryDonut() {
print "Pack donut with pink Packing! ";
return $this;
}
}
$strawberryDonut = new StrawberryDonut();
$strawberryDonut->make();
اما گفتیم که نیازی به تکرار کدهای تهیه دونات نیست. چراکه فرآیند تهیه دونات به جز بخش تزئین، یک فرآیند قراردادی و تکراری است. بنابراین بخش های تکراری کد را از طریق استفاده از abstract به یک قرارداد تبدیل می کنیم:
abstract class DonutTemplate {
public function make() {
return $this
->makeDough()
->moldDonut()
->fryDonut()
->addDressing()
->packDonut();
}
protected function makeDough() {
print "make donut dough, first. ";
return $this;
}
protected function moldDonut() {
print "then, mold donut to have a wheel shape. ";
return $this;
}
protected function fryDonut() {
print "fry the donut carefully. ";
return $this;
}
protected abstract function addDressing();
protected abstract function packDonut();
}
class ChocolateDonut extends DonutTemplate {
protected function addDressing()
{
print "Add enough chocolate on the donut!";
return $this;
}
protected function packDonut()
{
print "Pack donut with brown Packing! ";
return $this;
}
}
class StrawberryDonut extends DonutTemplate {
protected function addDressing()
{
print "Add enough strawberry sauce on the donut!";
return $this;
}
protected function packDonut()
{
print "Pack donut with pink Packing! ";
return $this;
}
}
$chocoDonut = new ChocolateDonut();
$chocoDonut->make();
همانطور که در کد می بینید، یک کلاس abstract کلاسی است که شامل حداقل یک متد abstract باشد. متدهای abstract متدهایی هستند که فاقد پیاده سازی هستند و فقط کلاس های فرزند را وادار می کنند آن متدها را در خود پیاده سازی کنند. در کد بالا با استفاده از کلمه کلیدی extends کلاس فرزند را وادار کرده ایم از کلاس والد abstract تبعیت کند. در صورتی که کلاس ChocolateDonut، متد addDressing را پیاده سازی نکند، برنامه با ارور مواجه می شود.
از این پس برای ساخت دونات های جدید با هر نوع سس تزئینی، کافی است کلاس دونات جدید، کلاس abstract با نام DonutTemplate را پیاده سازی نماید.
و اینگونه هستش که برنامه نویسی شی گرا لذت بخش میشه احسنت.
???
ممنونم جناب صالحی عزیز :)
ممنون بایت مطالب فوق العادتون ، مثال ها واقعا قابل درک و عالی هستن ♥
ممنونم لطف دارید جناب شهسواری :)
خیلی ممنون خوب بود.
ممنون بابت نکاتی که بیان کردید، اینطور مثال زدن، کار هر کسی نیست. موفق باشید
خیلی روان و عالی بود دمتون گرم
واقعن عالی توضیح دادید مشتاقم بیشتر دنبال کنم اموزش ها این چنینی رو
خیلی توضیح مختصر و عالی بود
واقعا حرف نداشت عالی
واقعا قشنگ بود