CodeGym /جاوا بلاگ /Random-UR /ٹھوس: جاوا میں کلاس ڈیزائن کے پانچ بنیادی اصول
John Squirrels
سطح
San Francisco

ٹھوس: جاوا میں کلاس ڈیزائن کے پانچ بنیادی اصول

گروپ میں شائع ہوا۔
کلاسیں ایپلی کیشنز کی تعمیر کا حصہ ہیں۔ جیسے عمارت میں اینٹ۔ ناقص تحریری کلاسیں آخرکار مسائل کا سبب بن سکتی ہیں۔ ٹھوس: جاوا میں کلاس ڈیزائن کے پانچ بنیادی اصول - 1یہ سمجھنے کے لیے کہ آیا کوئی کلاس ٹھیک سے لکھی گئی ہے، آپ چیک کر سکتے ہیں کہ یہ کس طرح "معیار کے معیارات" تک پہنچتی ہے۔ جاوا میں، یہ نام نہاد SOLID اصول ہیں، اور ہم ان کے بارے میں بات کرنے جا رہے ہیں۔

جاوا میں ٹھوس اصول

SOLID ایک مخفف ہے جو OOP اور کلاس ڈیزائن کے پہلے پانچ اصولوں کے بڑے حروف سے بنایا گیا ہے۔ ان اصولوں کا اظہار رابرٹ مارٹن نے 2000 کی دہائی کے اوائل میں کیا تھا، اور پھر اس کا مخفف بعد میں مائیکل فیدرز نے متعارف کرایا تھا۔ یہاں ٹھوس اصول ہیں:
  1. واحد ذمہ داری کا اصول
  2. کھلا بند اصول
  3. Liskov متبادل اصول
  4. انٹرفیس علیحدگی کا اصول
  5. انحصار الٹا اصول

واحد ذمہ داری کا اصول (SRP)

یہ اصول بتاتا ہے کہ کسی بھی طبقے کو تبدیل کرنے کی ایک سے زیادہ وجہ نہیں ہونی چاہیے۔ ہر شے کی ایک ذمہ داری ہوتی ہے، جو کلاس میں مکمل طور پر شامل ہوتی ہے۔ کلاس کی تمام خدمات کا مقصد اس ذمہ داری کی حمایت کرنا ہے۔ اگر ضروری ہو تو ایسی کلاسوں میں ترمیم کرنا ہمیشہ آسان ہو گا، کیونکہ یہ واضح ہے کہ کلاس کیا ہے اور اس کے لیے ذمہ دار نہیں ہے۔ دوسرے لفظوں میں، ہم تبدیلیاں کرنے کے قابل ہو جائیں گے اور نتائج سے خوفزدہ نہیں ہوں گے، یعنی دیگر اشیاء پر اثرات۔ مزید برآں، اس طرح کے کوڈ کی جانچ کرنا بہت آسان ہے، کیونکہ آپ کے ٹیسٹ ایک فنکشنلٹی کو باقی سب سے الگ تھلگ کر رہے ہیں۔ ایک ماڈیول کا تصور کریں جو آرڈرز پر کارروائی کرتا ہے۔ اگر کوئی آرڈر صحیح طریقے سے بنتا ہے، تو یہ ماڈیول اسے ڈیٹا بیس میں محفوظ کرتا ہے اور آرڈر کی تصدیق کے لیے ای میل بھیجتا ہے:
public class OrderProcessor {

    public void process(Order order){
        if (order.isValid() && save(order)) {
            sendConfirmationEmail(order);
        }
    }

    private boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }

    private void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}
یہ ماڈیول تین وجوہات کی بنا پر تبدیل ہو سکتا ہے۔ سب سے پہلے، پروسیسنگ آرڈرز کی منطق بدل سکتی ہے۔ دوسرا، آرڈرز کو محفوظ کرنے کا طریقہ (ڈیٹا بیس کی قسم) تبدیل ہو سکتا ہے۔ تیسرا، تصدیق کے بھیجنے کا طریقہ بدل سکتا ہے (مثال کے طور پر، فرض کریں کہ ہمیں ای میل کے بجائے ٹیکسٹ پیغام بھیجنے کی ضرورت ہے)۔ واحد ذمہ داری کے اصول کا مطلب یہ ہے کہ اس مسئلے کے تین پہلو دراصل تین مختلف ذمہ داریاں ہیں۔ اس کا مطلب ہے کہ وہ مختلف کلاسوں یا ماڈیولز میں ہونے چاہئیں۔ متعدد اداروں کو یکجا کرنا جو مختلف اوقات میں اور مختلف وجوہات کی بناء پر تبدیل ہو سکتے ہیں ایک ناقص ڈیزائن فیصلہ سمجھا جاتا ہے۔ ایک ماڈیول کو تین الگ الگ ماڈیولز میں تقسیم کرنا بہت بہتر ہے، جن میں سے ہر ایک ایک فنکشن انجام دیتا ہے:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}

public class ConfirmationEmailSender {
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}

public class OrderProcessor {
    public void process(Order order){

        MySQLOrderRepository repository = new MySQLOrderRepository();
        ConfirmationEmailSender mailSender = new ConfirmationEmailSender();

        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }

}

اوپن کلوزڈ پرنسپل (او سی پی)

اس اصول کو اس طرح بیان کیا گیا ہے: سافٹ ویئر اداروں (کلاسز، ماڈیولز، فنکشنز، وغیرہ) کو توسیع کے لیے کھلا ہونا چاہیے، لیکن ترمیم کے لیے بند ہونا چاہیے ۔ اس کا مطلب ہے کہ کلاس کے موجودہ کوڈ میں تبدیلی کیے بغیر کلاس کے بیرونی رویے کو تبدیل کرنا ممکن ہونا چاہیے۔ اس اصول کے مطابق، کلاسز کو اس طرح ڈیزائن کیا گیا ہے کہ کسی کلاس کو مخصوص حالات میں فٹ کرنے کے لیے اسے بڑھانا اور کچھ فنکشنز کو اوور رائیڈ کرنے کی ضرورت ہے۔ اس کا مطلب یہ ہے کہ نظام کو لچکدار ہونا چاہیے، ماخذ کوڈ کو تبدیل کیے بغیر بدلتے ہوئے حالات میں کام کرنے کے قابل ہونا چاہیے۔ آرڈر پروسیسنگ میں شامل ہماری مثال کو جاری رکھتے ہوئے، فرض کریں کہ ہمیں آرڈر پر کارروائی کرنے سے پہلے اور تصدیقی ای میل بھیجے جانے کے بعد کچھ اقدامات کرنے کی ضرورت ہے۔ کلاس کو تبدیل کرنے کے بجائے OrderProcessor، ہم کھلے بند اصول کی خلاف ورزی کیے بغیر اپنے مقصد کو پورا کرنے کے لیے اسے بڑھا دیں گے:
public class OrderProcessorWithPreAndPostProcessing extends OrderProcessor {

    @Override
    public void process(Order order) {
        beforeProcessing();
        super.process(order);
        afterProcessing();
    }

    private void beforeProcessing() {
        // Take some action before processing the order
    }

    private void afterProcessing() {
        // Take some action after processing the order
    }
}

Liskov متبادل اصول (LSP)

یہ کھلے بند اصول کی ایک تبدیلی ہے جس کا ہم نے پہلے ذکر کیا ہے۔ اس کی وضاحت اس طرح کی جا سکتی ہے: کسی پروگرام کی خصوصیات کو تبدیل کیے بغیر اشیاء کو ذیلی طبقات کی اشیاء سے تبدیل کیا جا سکتا ہے۔ اس کا مطلب یہ ہے کہ بیس کلاس کو بڑھا کر تخلیق کردہ کلاس کو اپنے طریقوں کو اوور رائڈ کرنا چاہیے تاکہ کلائنٹ کے نقطہ نظر سے فعالیت پر سمجھوتہ نہ کیا جائے۔ یعنی، اگر کوئی ڈویلپر آپ کی کلاس بڑھاتا ہے اور اسے کسی ایپلیکیشن میں استعمال کرتا ہے، تو اسے کسی بھی اوور رائڈ شدہ طریقوں کے متوقع رویے کو تبدیل نہیں کرنا چاہیے۔ ذیلی طبقات کو بیس کلاس کے طریقوں کو اوور رائڈ کرنا چاہیے تاکہ کلائنٹ کے نقطہ نظر سے فعالیت کو توڑا نہ جائے۔ اس کو ہم درج ذیل مثال میں تفصیل سے دیکھ سکتے ہیں۔ فرض کریں کہ ہمارے پاس ایک کلاس ہے جو آرڈر کی توثیق کرنے اور یہ جانچنے کے لیے ذمہ دار ہے کہ آیا آرڈر میں موجود تمام سامان اسٹاک میں ہیں۔ اس کلاس کا ایک isValid()طریقہ ہے جو صحیح یا غلط کو لوٹاتا ہے :
public class OrderStockValidator {

    public boolean isValid(Order order) {
        for (Item item : order.getItems()) {
            if (!item.isInStock()) {
                return false;
            }
        }

        return true;
    }
}
یہ بھی فرض کریں کہ کچھ آرڈرز کی توثیق دوسرے سے مختلف طریقے سے کرنے کی ضرورت ہے، جیسے کہ کچھ آرڈرز کے لیے ہمیں یہ چیک کرنا ہوگا کہ آیا آرڈر میں موجود تمام سامان اسٹاک میں ہیں یا نہیں اور آیا تمام سامان پیک کیا گیا ہے۔ ایسا کرنے کے لیے، ہم OrderStockValidatorکلاس بنا کر کلاس کو بڑھاتے ہیں OrderStockAndPackValidator:
public class OrderStockAndPackValidator extends OrderStockValidator {

    @Override
    public boolean isValid(Order order) {
        for (Item item : order.getItems()) {
            if ( !item.isInStock() || !item.isPacked() ){
                throw new IllegalStateException(
                     String.format("Order %d is not valid!", order.getId())
                );
            }
        }

        return true;
    }
}
لیکن یہاں ہم نے Liskov متبادل اصول کی خلاف ورزی کی ہے، کیونکہ اگر آرڈر کی توثیق میں ناکام ہو جاتا ہے تو غلط واپس کرنے کے بجائے، ہمارا طریقہ ایک پھینک دیتا ہے IllegalStateException۔ اس کوڈ کو استعمال کرنے والے کلائنٹ اس کی توقع نہیں کرتے ہیں: وہ صحیح یا غلط کی واپسی کی قیمت کی توقع کرتے ہیں ۔ یہ رن ٹائم کی خرابیوں کا باعث بن سکتا ہے۔

انٹرفیس سیگریگیشن پرنسپل (ISP)

یہ اصول مندرجہ ذیل بیان سے نمایاں ہے: کلائنٹ کو ان طریقوں کو نافذ کرنے پر مجبور نہیں کیا جانا چاہئے جو وہ استعمال نہیں کریں گے ۔ انٹرفیس کی علیحدگی کے اصول کا مطلب یہ ہے کہ انٹرفیس جو بہت "موٹے" ہیں ان کو چھوٹے، زیادہ مخصوص میں تقسیم کیا جانا چاہیے، تاکہ چھوٹے انٹرفیس استعمال کرنے والے کلائنٹ صرف ان طریقوں کے بارے میں جانیں جن کی انہیں اپنے کام کے لیے ضرورت ہے۔ نتیجے کے طور پر، جب انٹرفیس کا طریقہ تبدیل ہوتا ہے، تو کوئی بھی کلائنٹ جو اس طریقہ کو استعمال نہیں کرتا ہے اسے تبدیل نہیں ہونا چاہیے۔ اس مثال پر غور کریں: ایلکس، ایک ڈویلپر نے ایک "رپورٹ" انٹرفیس بنایا ہے اور دو طریقے شامل کیے ہیں: generateExcel()اور generatedPdf(). اب ایک کلائنٹ اس انٹرفیس کو استعمال کرنا چاہتا ہے، لیکن صرف پی ڈی ایف فارمیٹ میں رپورٹس استعمال کرنا چاہتا ہے، ایکسل میں نہیں۔ کیا یہ فعالیت اس کلائنٹ کو مطمئن کرے گی؟ نہیں، کلائنٹ کو دو طریقے لاگو کرنے ہوں گے، جن میں سے ایک کی زیادہ تر ضرورت نہیں ہے اور یہ صرف الیکس کی بدولت موجود ہے، جس نے سافٹ ویئر ڈیزائن کیا۔ کلائنٹ یا تو ایک مختلف انٹرفیس استعمال کرے گا یا Excel رپورٹس کے طریقہ کار کے ساتھ کچھ نہیں کرے گا۔ تو اس کا حل کیا ہے؟ یہ موجودہ انٹرفیس کو دو چھوٹے حصوں میں تقسیم کرنا ہے۔ ایک پی ڈی ایف رپورٹس کے لیے، دوسرا ایکسل رپورٹس کے لیے۔ یہ کلائنٹس کو صرف وہی فعالیت استعمال کرنے دیتا ہے جس کی انہیں ضرورت ہے۔

انحصار الٹا اصول (DIP)

جاوا میں، اس ٹھوس اصول کو اس طرح بیان کیا گیا ہے: نظام کے اندر انحصار تجرید کی بنیاد پر بنایا گیا ہے ۔ اعلیٰ سطح کے ماڈیول نچلے درجے کے ماڈیولز پر منحصر نہیں ہوتے ہیں۔ خلاصہ تفصیلات پر منحصر نہیں ہونا چاہئے۔ تفصیلات کا انحصار تجرید پر ہونا چاہیے۔ سافٹ ویئر کو اس طرح ڈیزائن کرنے کی ضرورت ہے کہ مختلف ماڈیول خود موجود ہوں اور تجرید کے ذریعے ایک دوسرے سے جڑے ہوں۔ اس اصول کا ایک کلاسک اطلاق بہار کا فریم ورک ہے۔ بہار کے فریم ورک میں، تمام ماڈیولز کو الگ الگ اجزاء کے طور پر لاگو کیا جاتا ہے جو ایک ساتھ کام کر سکتے ہیں۔ وہ اتنے خود مختار ہیں کہ انہیں بہار کے فریم ورک کے علاوہ پروگرام کے ماڈیولز میں بھی آسانی سے استعمال کیا جا سکتا ہے۔ یہ بند اور کھلے اصولوں کے انحصار کی بدولت حاصل کیا جاتا ہے۔ تمام ماڈیول صرف تجرید تک رسائی فراہم کرتے ہیں، جسے کسی اور ماڈیول میں استعمال کیا جا سکتا ہے۔ آئیے ایک مثال سے اس کی وضاحت کرنے کی کوشش کرتے ہیں۔ واحد ذمہ داری کے اصول کی بات کرتے ہوئے، ہم نے OrderProcessorطبقے پر غور کیا۔ آئیے اس کلاس کے کوڈ پر ایک اور نظر ڈالتے ہیں:
public class OrderProcessor {
    public void process(Order order){

        MySQLOrderRepository repository = new MySQLOrderRepository();
        ConfirmationEmailSender mailSender = new ConfirmationEmailSender();

        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }

}
اس مثال میں، ہماری OrderProcessorکلاس دو مخصوص کلاسوں پر منحصر ہے: MySQLOrderRepositoryاور ConfirmationEmailSender. ہم ان کلاسوں کا کوڈ بھی پیش کریں گے:
public class MySQLOrderRepository {
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}

public class ConfirmationEmailSender {
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }
}
یہ کلاسز اس سے بہت دور ہیں جسے ہم تجرید کہتے ہیں۔ اور انحصار الٹنے کے اصول کے نقطہ نظر سے، یہ بہتر ہوگا کہ ہم مخصوص نفاذ کے بجائے کچھ تجریدات بنا کر شروع کریں جن کے ساتھ ہم مستقبل میں کام کر سکتے ہیں۔ آئیے دو انٹرفیس بنائیں: MailSenderاور OrderRepository)۔ یہ ہمارے خلاصے ہوں گے:
public interface MailSender {
    void sendConfirmationEmail(Order order);
}

public interface OrderRepository {
    boolean save(Order order);
}
اب ہم ان انٹرفیس کو ان کلاسوں میں لاگو کرتے ہیں جو اس کے لیے پہلے ہی تیار کی جا چکی ہیں:
public class ConfirmationEmailSender implements MailSender {

    @Override
    public void sendConfirmationEmail(Order order) {
        String name = order.getCustomerName();
        String email = order.getCustomerEmail();

        // Send an email to the customer
    }

}

public class MySQLOrderRepository implements OrderRepository {

    @Override
    public boolean save(Order order) {
        MySqlConnection connection = new MySqlConnection("database.url");
        // Save the order in the database

        return true;
    }
}
ہم نے تیاری کا کام کیا تاکہ ہماری OrderProcessorکلاس کا انحصار ٹھوس تفصیلات پر نہیں بلکہ تجرید پر ہو۔ ہم کلاس کنسٹرکٹر میں اپنی انحصار شامل کرکے اسے تبدیل کریں گے:
public class OrderProcessor {

    private MailSender mailSender;
    private OrderRepository repository;

    public OrderProcessor(MailSender mailSender, OrderRepository repository) {
        this.mailSender = mailSender;
        this.repository = repository;
    }

    public void process(Order order){
        if (order.isValid() && repository.save(order)) {
            mailSender.sendConfirmationEmail(order);
        }
    }
}
اب ہماری کلاس کا انحصار خلاصہ پر ہے، مخصوص نفاذ پر نہیں۔ OrderProcessorکسی چیز کی تخلیق کے وقت مطلوبہ انحصار شامل کرکے ہم آسانی سے اس کے رویے کو تبدیل کر سکتے ہیں ۔ ہم نے جاوا میں ٹھوس ڈیزائن کے اصولوں کا جائزہ لیا ہے۔ آپ کوڈ جیم کورس میں عمومی طور پر OOP اور جاوا پروگرامنگ کی بنیادی باتیں — کچھ بھی بورنگ نہیں اور سینکڑوں گھنٹے کی مشق — کے بارے میں مزید جانیں گے۔ کچھ کاموں کو حل کرنے کا وقت :)
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION