CodeGym /جاوا بلاگ /Random-UR /حکمت عملی ڈیزائن پیٹرن
John Squirrels
سطح
San Francisco

حکمت عملی ڈیزائن پیٹرن

گروپ میں شائع ہوا۔
ہائے! آج کے سبق میں، ہم حکمت عملی کے پیٹرن کے بارے میں بات کریں گے۔ پچھلے اسباق میں، ہم پہلے ہی مختصر طور پر وراثت کے تصور سے واقف ہو چکے ہیں۔ اگر آپ بھول گئے ہیں تو، میں آپ کو یاد دلاؤں گا کہ اس اصطلاح سے مراد ایک عام پروگرامنگ ٹاسک کا معیاری حل ہے۔ CodeGym میں، ہم اکثر کہتے ہیں کہ آپ تقریباً کسی بھی سوال کا جواب گوگل کر سکتے ہیں۔ اس کی وجہ یہ ہے کہ آپ کا کام، جو کچھ بھی ہو، شاید پہلے ہی کسی اور نے کامیابی سے حل کر دیا ہو۔ پیٹرن سب سے عام کاموں کے لیے آزمائے گئے اور سچے حل ہیں، یا مشکل حالات کو حل کرنے کے طریقے۔ یہ "پہیوں" کی طرح ہیں جو آپ کو خود سے دوبارہ ایجاد کرنے کی ضرورت نہیں ہے، لیکن آپ کو یہ جاننے کی ضرورت ہے کہ انہیں کیسے اور کب استعمال کرنا ہے :) پیٹرن کا ایک اور مقصد یکساں فن تعمیر کو فروغ دینا ہے۔ کسی اور کا کوڈ پڑھنا کوئی آسان کام نہیں ہے! ہر کوئی مختلف کوڈ لکھتا ہے، کیونکہ ایک ہی کام کو کئی طریقوں سے حل کیا جا سکتا ہے۔ لیکن پیٹرن کے استعمال سے مختلف پروگرامرز کو کوڈ کی ہر سطر میں تلاش کیے بغیر پروگرامنگ کی منطق کو سمجھنے میں مدد ملتی ہے (یہاں تک کہ جب اسے پہلی بار دیکھا گیا ہو!) آج ہم "حکمت عملی" کہلانے والے سب سے عام ڈیزائن پیٹرن میں سے ایک کو دیکھتے ہیں۔ ڈیزائن پیٹرن: حکمت عملی - 2تصور کریں کہ ہم ایک ایسا پروگرام لکھ رہے ہیں جو Conveyance اشیاء کے ساتھ فعال طور پر کام کرے گا۔ اس سے کوئی فرق نہیں پڑتا کہ ہمارا پروگرام بالکل کیا کرتا ہے۔ ہم نے ایک کنوینس پیرنٹ کلاس اور تین چائلڈ کلاسز کے ساتھ کلاس کا درجہ بندی بنایا ہے: Sedan ، Truck اور F1Car ۔
public class Conveyance {

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {

       System.out.println("Braking!");
   }
}

public class Sedan extends Conveyance {
}

public class Truck extends Conveyance {
}

public class F1Car extends Conveyance {
}
تینوں چائلڈ کلاسز کو والدین سے دو معیاری طریقے وراثت میں ملے ہیں: go() اور stop() ۔ ہمارا پروگرام بہت آسان ہے: ہماری کاریں صرف آگے بڑھ سکتی ہیں اور بریک لگا سکتی ہیں۔ اپنے کام کو جاری رکھتے ہوئے، ہم نے کاروں کو ایک نیا طریقہ دینے کا فیصلہ کیا: fill() (مطلب، "گیس ٹینک بھریں")۔ ہم نے اسے Conveyance پیرنٹ کلاس میں شامل کیا:
public class Conveyance {

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {

       System.out.println("Braking!");
   }

   public void fill() {
       System.out.println("Refueling!");
   }
}
کیا واقعی اتنی سادہ صورتحال میں مسائل پیدا ہو سکتے ہیں؟ درحقیقت، ان کے پاس پہلے ہی... ڈیزائن پیٹرن: حکمت عملی - 3
public class Stroller extends Conveyance {

   public void fill() {

       // Hmm... This is a stroller for children. It doesn't need to be refueled :/
   }
}
ہمارے پروگرام میں اب ایک کنوینس (ایک بچہ گھومنے والا) ہے جو عام تصور میں اچھی طرح سے فٹ نہیں ہوتا ہے۔ اس میں پیڈل ہوسکتے ہیں یا ریڈیو سے کنٹرول کیا جاسکتا ہے، لیکن ایک چیز یقینی ہے - اس میں گیس ڈالنے کی کوئی جگہ نہیں ہوگی۔ ہمارے طبقاتی درجہ بندی نے عام طریقوں کو ان کلاسوں سے وراثت میں ملایا ہے جن کی ضرورت نہیں ہے۔ اس صورت حال میں ہمیں کیا کرنا چاہیے؟ ٹھیک ہے، ہم سٹرولر کلاس میں فل() طریقہ کو اوور رائیڈ کر سکتے ہیں تاکہ جب آپ سٹرولر کو ایندھن بھرنے کی کوشش کریں تو کچھ نہ ہو:
public class Stroller extends Conveyance {

   @Override
   public void fill() {
       System.out.println("A stroller cannot be refueled!");
   }
}
لیکن اسے شاید ہی ایک کامیاب حل کہا جا سکے اگر ڈپلیکیٹ کوڈ کے علاوہ کوئی اور وجہ نہ ہو۔ مثال کے طور پر، زیادہ تر کلاسز پیرنٹ کلاس کا طریقہ استعمال کریں گی، لیکن باقی اسے اوور رائڈ کرنے پر مجبور ہوں گی۔ اگر ہمارے پاس 15 کلاسز ہیں اور ہمیں ان میں سے 5-6 میں رویے کو اوور رائڈ کرنا چاہیے، تو کوڈ کی نقل کافی وسیع ہو جائے گی۔ شاید انٹرفیس ہماری مدد کر سکتے ہیں؟ مثال کے طور پر، اس طرح:
public interface Fillable {

   public void fill();
}
ہم ایک بھرنے کے قابل انٹرفیس ایک فل() طریقہ سے بنائیں گے۔ پھر، وہ نقل و حمل جن کو ایندھن بھرنے کی ضرورت ہے وہ اس انٹرفیس کو نافذ کرے گی، جب کہ دیگر نقل و حمل (مثال کے طور پر، ہمارے بچے کی سٹرولر) نہیں کریں گے۔ لیکن یہ آپشن ہمارے لیے موزوں نہیں ہے۔ مستقبل میں، ہمارا طبقاتی درجہ بندی بہت بڑا ہو سکتا ہے (ذرا تصور کریں کہ دنیا میں کتنی مختلف قسم کی نقل و حمل ہیں)۔ ہم نے وراثت میں شامل پچھلے ورژن کو ترک کر دیا، کیونکہ ہم fill() طریقہ کو کئی بار، اوور رائڈ نہیں کرنا چاہتے ۔ اب ہمیں اسے ہر کلاس میں نافذ کرنا ہوگا! اور اگر ہمارے پاس 50 ہیں تو کیا ہوگا؟ اور اگر ہمارے پروگرام میں بار بار تبدیلیاں کی جائیں گی (اور یہ تقریباً ہمیشہ حقیقی پروگراموں کے لیے درست ہے!)، تو ہمیں تمام 50 کلاسوں میں جلدی کرنا پڑے گا اور ان میں سے ہر ایک کے رویے کو دستی طور پر تبدیل کرنا پڑے گا۔ تو، آخر میں، ہمیں اس صورت حال میں کیا کرنا چاہئے؟ اپنے مسئلے کو حل کرنے کے لیے، ہم ایک مختلف طریقہ منتخب کریں گے۔ یعنی، ہم اپنی کلاس کے رویے کو کلاس سے الگ کر دیں گے۔ اس کا کیا مطلب ہے؟ جیسا کہ آپ جانتے ہیں، ہر شے کی حالت (ڈیٹا کا ایک سیٹ) اور طرز عمل (طریقوں کا ایک مجموعہ) ہوتا ہے۔ ہماری کنوینس کلاس کا رویہ تین طریقوں پر مشتمل ہے: go() ، stop() اور fill() ۔ پہلے دو طریقے ٹھیک ہیں جیسے وہ ہیں۔ لیکن ہم تیسرے طریقہ کو کنوینس کلاس سے باہر لے جائیں گے۔ یہ طرز عمل کو کلاس سے الگ کر دے گا (زیادہ درست طور پر، یہ رویے کا صرف ایک حصہ الگ کرے گا، کیونکہ پہلے دو طریقے وہیں رہیں گے جہاں وہ ہیں)۔ تو ہمیں اپنا fill() طریقہ کہاں رکھنا چاہیے ؟ کچھ بھی ذہن میں نہیں آتا:/ ایسا لگتا ہے کہ یہ بالکل وہی ہے جہاں اسے ہونا چاہئے۔ ہم اسے ایک الگ انٹرفیس میں منتقل کریں گے: FillStrategy !
public interface FillStrategy {

   public void fill();
}
ہمیں ایسے انٹرفیس کی ضرورت کیوں ہے؟ یہ سب سیدھا ہے۔ اب ہم کئی کلاسز بنا سکتے ہیں جو اس انٹرفیس کو نافذ کرتی ہیں:
public class HybridFillStrategy implements FillStrategy {

   @Override
   public void fill() {
       System.out.println("Refuel with gas or electricity — your choice!");
   }
}

public class F1PitstopStrategy implements FillStrategy {

   @Override
   public void fill() {
       System.out.println("Refuel with gas only after all other pit stop procedures are complete!");
   }
}

public class StandardFillStrategy implements FillStrategy {
   @Override
   public void fill() {
       System.out.println("Just refuel with gas!");
   }
}
ہم نے تین طرز عمل کی حکمت عملی بنائی: ایک عام کاروں کے لیے، ایک ہائبرڈ کے لیے، اور ایک فارمولا 1 ریس کاروں کے لیے۔ ہر حکمت عملی ایک مختلف ایندھن بھرنے والے الگورتھم کو نافذ کرتی ہے۔ ہمارے معاملے میں، ہم کنسول پر صرف ایک تار دکھاتے ہیں، لیکن ہر طریقہ میں کچھ پیچیدہ منطق ہو سکتی ہے۔ ہم آگے کیا کریں؟
public class Conveyance {

   FillStrategy fillStrategy;

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

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {
       System.out.println("Braking!");
   }

}
ہم اپنے FillStrategy انٹرفیس کو Conveyance پیرنٹ کلاس میں بطور فیلڈ استعمال کرتے ہیں۔ نوٹ کریں کہ ہم کسی مخصوص نفاذ کی نشاندہی نہیں کر رہے ہیں — ہم ایک انٹرفیس استعمال کر رہے ہیں۔ کار کی کلاسوں کو FillStrategy انٹرفیس کے مخصوص نفاذ کی ضرورت ہوگی:
public class F1Car extends Conveyance {

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

public class HybridCar extends Conveyance {

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

public class Sedan extends Conveyance {

   public Sedan() {
       this.fillStrategy = new StandardFillStrategy();
   }
}
آئیے دیکھتے ہیں کہ ہمیں کیا ملا!
public class Main {

   public static void main(String[] args) {

       Conveyance sedan = new Sedan();
       Conveyance hybrid = new HybridCar();
       Conveyance f1car = new F1Car();

       sedan.fill();
       hybrid.fill();
       f1car.fill();
   }
}
کنسول آؤٹ پٹ:

Just refuel with gas! 
Refuel with gas or electricity — your choice! 
Refuel with gas only after all other pit stop procedures are complete!
زبردست! ایندھن بھرنے کا عمل کام کرتا ہے جیسا کہ اسے کرنا چاہئے! ویسے، کنسٹرکٹر میں حکمت عملی کو بطور پیرامیٹر استعمال کرنے سے ہمیں کوئی چیز نہیں روکتی! مثال کے طور پر، اس طرح:
public class Conveyance {

   private FillStrategy fillStrategy;

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

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

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {
       System.out.println("Braking!");
   }
}

public class Sedan extends Conveyance {

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



public class HybridCar extends Conveyance {

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

public class F1Car extends Conveyance {

   public F1Car() {
       super(new F1PitstopStrategy());
   }
}
آئیے اپنا مین () طریقہ چلائیں (جو کہ کوئی تبدیلی نہیں ہے)۔ ہمیں ایک ہی نتیجہ ملتا ہے! کنسول آؤٹ پٹ:

Just refuel with gas! 
Refuel with gas or electricity — your choice! 
Refuel with gas only after all other pit stop procedures are complete!
حکمت عملی ڈیزائن پیٹرن الگورتھم کے خاندان کی وضاحت کرتا ہے، ان میں سے ہر ایک کو سمیٹتا ہے، اور اس بات کو یقینی بناتا ہے کہ وہ قابل تبادلہ ہیں۔ یہ آپ کو الگورتھم میں ترمیم کرنے دیتا ہے اس سے قطع نظر کہ وہ کلائنٹ کے ذریعہ کیسے استعمال کیے جاتے ہیں (یہ تعریف، کتاب "ہیڈ فرسٹ ڈیزائن پیٹرنز" سے لی گئی ہے، میرے لیے بہترین معلوم ہوتی ہے)۔ ڈیزائن پیٹرن: حکمت عملی - 4ہم نے پہلے ہی الگورتھم کے خاندان کی وضاحت کر دی ہے جس میں ہماری دلچسپی ہے (کاروں کو ایندھن بھرنے کے طریقے) مختلف نفاذ کے ساتھ الگ الگ انٹرفیس میں۔ ہم نے انہیں گاڑی سے ہی الگ کیا۔ اب اگر ہمیں کسی خاص ایندھن بھرنے والے الگورتھم میں کوئی تبدیلی کرنے کی ضرورت ہے، تو اس سے ہماری کار کی کلاسز پر کوئی اثر نہیں پڑے گا۔ اور تبادلہ کرنے کی صلاحیت حاصل کرنے کے لیے، ہمیں اپنی Conveyance کلاس میں صرف ایک سیٹر طریقہ شامل کرنے کی ضرورت ہے :
public class Conveyance {

   FillStrategy fillStrategy;

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

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {
       System.out.println("Braking!");
   }

   public void setFillStrategy(FillStrategy fillStrategy) {
       this.fillStrategy = fillStrategy;
   }
}
اب ہم پرواز پر حکمت عملی تبدیل کر سکتے ہیں:
public class Main {

   public static void main(String[] args) {

       Stroller stroller= new Stroller();
       stroller.setFillStrategy(new StandardFillStrategy());

       stroller.fill();
   }
}
اگر بچے کی ٹہلنے والے اچانک پٹرول پر چلنے لگتے ہیں، تو ہمارا پروگرام اس منظر نامے کو سنبھالنے کے لیے تیار ہو جائے گا :) اور بس! آپ نے ایک اور ڈیزائن پیٹرن سیکھا ہے جو حقیقی پروجیکٹس پر کام کرتے وقت بلاشبہ ضروری اور مددگار ثابت ہوگا :) اگلی بار تک!
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION