Friday, July 28, 2017

ইনভার্শন অব কন্ট্রোল কী (What is Inversion of Control)?

আমরা বাস্তব জগেতে যখন কোনো কিছু তৈরি করি, তখন কাজগুলোকে ছোট ছোট বিভিন্ন উপাদানে বিভক্ত করে ফেলি। যেমন- গাড়ির ক্ষেত্রে - চাকা, স্টিয়ারিং, chassis, দরজা, ইত্যাদি। এগুলো আরও ছোট ছোট অংশে বিভক্তর করে এদেরকে আলাদা আলাদা ভাবে তৈরি করা হয় এবং পরে একসঙ্গে জুড়ে দেওয়া হয়। 

একইভাবে অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিংয়ের মূল ব্যপার হলো বাস্তব জগতের সঙ্গে সাদৃশ্য রেখে কোনো সমস্যা সমাধান করা। এতে অনেকগুলো অবজেক্ট থাকা যারা নিদির্ষ্ট কোনো কাজ করে এবং এগুলোকে একত্রে জুড়ে দিয়ে একটি বড় অবজেক্ট তৈরি করা হয়। প্রত্যেকটি অবজেক্ট একটি বাস্তব জগতের কোনো কিছুর প্রতিরূপ। Airplane অবজেক্ট একটি উড়োজাহাজকে নির্দেশ করতে পারে, সেভাবে একটি Purchase অবজেক্ট একটি বই কেনার বিভিন্ন ডেটা যেমন- দাম, বই অবজেক্টের রেফারেন্স, কত কপি ইত্যাদি নির্দেশ করতে পারে। 

একটি অবজেক্টকে সঠিকভাবে কাজ করতে হলে অনেক সময়ই অন্য এক বা একাধিক অবজেক্টের উপর নির্ভর করতে হয়। যে অবজেক্টের উপর নির্ভর করে কোনো কাজ করতে হয় তাকে অন্য অবজেক্টটির ডিপেডেন্সি বলা হয়। অর্থাৎ A কে কাজ করতে হলে যদি B এর উপর নির্ভর করতে হয়, তাহলে B, A এর ডিপেডেন্সি।

এখন মনে করুন, আপনি একটি ইমেইল অ্যাপ্লিকেশন লিখবেন। এই অ্যাপ্লিকেশনের বেশ কতগুলো অংশ থাকতে পারে।

এক- একটি টেক্সট এডিটরের প্রয়োজন হবে, যা একটি অবজেক্ট। 
দুই- আপনি যে টেক্সটটি লিখবেন, সেটিকে নির্দেশ করতে একটি অবজেক্ট প্রয়োজন হবে।
তিন- ইমেইল সেন্ড করার আগে অবশ্যই আপনি বানানগুলো ঠিক করে নিতে চান, সেক্ষেত্রে বানান শুদ্ধিকরণ একটি অবজেক্টের প্রয়োজন হবে। 
চার- আপনাকে ইমেইলটি পাঠানোর জন্য ইমেইল অ্যাড্রেস প্রয়োজন। এগুলোর জন্য একটি অ্যাড্রেসবুক অবজেক্টের প্রয়োজন হবে, যেখানে আপানার সব ইমেইল অ্যাড্রেসগুলো রয়েছে। 
পাঁচ- একটি ইমেইলার অবজেক্ট যে কিনা ইমেইলটি ইন্টারনেট ব্যবহার করে গন্তব্যে পৌঁছানোর কাজটি করবে। 

ইত্যাদি ..।

তাহলে দেখা যাচ্ছে এই ইমেইলার অবজেক্টটি টেক্সট এডিটর, একচুয়াল টেক্সট, স্পেলচেকার এবং অ্যাড্রেসবুকের উপর নির্ভর করে। এগুলো ইমেইলার অবজেক্টের ডিপেডেন্সি। 

উদাহরণের সুবিধার্থে এবং মূল বিষয়টি সংক্ষিপ্তভাবে বোঝার জন্য মনে করুন, আপনার দুটি অবজেক্ট রয়েছে, একটি ইমেইলার অবজেক্ট যাতে একটি সেন্ড মেথড রয়েছে। আপনি ইমেইল সেন্ড করার আগে বানানগুলো ঠিক করে নিতে চান, সে জন্য প্রয়োজন SpellFixer অবজেক্ট। যেমন- 

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Emailer { 
    private SpellFixer spellFixer; 

    public Emailer() { 
        this.spellFixer = new SpellFixer(); 
    } 

    public void send(String text, String emailAddress) { 
        String fixedText = spellFixer.fixSpelling(text); 

        System.out.println("sending email to: " 
+ emailAddress + " with following text: " + fixedText); 
    } 
}

public class SpellFixer { 

    public String fixSpelling(String text) { 
        //business logic 
        //bla bla 

        return text; 
    } 
} 

এখন আপনি ইমেইলার ক্লাসটির অবজেক্ট তৈরি করে ইমেইল সেন্ড করতে পারবেন। 

1
2
Emailer emailer = new Emailer(); 
emailer.send("bla bla bla", "contact@bazlur.com");


উপরের এই প্রক্রিয়ায় কোনো সমস্যা নেই। এটি একটি সঠিক উপায়। 

তবে আমরা সব সময় যে ইংরেজিতে ইমেল লিখবো, এমনটি হওয়ার কোনো কারণ নেই। কখনো বাংলা বা অন্য কোনো ভাষাতে লিখতে পারি। সেক্ষেত্রে আমাদের এই উপরের সমাধানটি কাজ করবে না। ধরা যাক আমরা বাংলাতে একটি ইমেইল লিখতে চাই এবং এক্ষেত্রে একটি বাংলা স্পেলফিক্সার তৈরি করতে হবে। এক্ষেত্রে - 


1
2
Emailer emailer = new Emailer(); 
emailer.send("bla bla bla", "contact@bazlur.com");

তবে এটি সরাসরি আমাদের ইমেলারে প্লাগ করার কোনো উপায় নেই। যদিও বা আমরা করতে চাই, সেক্ষেত্রে আমাদের নতুন করে আরেকটি ইমেইলার তৈরি করতে হবে -

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class BanglaEmailer { 
    private BanglaSpellFixer spellFixer; 

    public BanglaEmailer() { 
        this.spellFixer = new BanglaSpellFixer(); 
    } 

    public void send(String text, String emailAddress) { 
        String fixedText = spellFixer.fixSpelling(text); 

        System.out.println("sending email to: " + emailAddress + " with following text: " + fixedText); 
    } 

    public static void main(String[] args) { 
        BanglaEmailer banglaEmailer = new BanglaEmailer(); 
        banglaEmailer.send("bla bla bla", "contact@bazlur.com"); 
    } 
} 

যদিও আমাদের ইমেইলার একইরকম, শুধুমাত্র বানান শুদ্ধ করার পক্রিয়া আলাদা হওয়ায় আমাদের দুটি অবজেক্ট তৈরি করতে হচ্ছে। এভাবে যদি আমাদের আরও অন্যান্য ভাষার জন্য লিখতে হয়, তাহলে পক্রিয়াটি আরও কঠিন হয়ে যায়। এছাড়াও এই সমাধানে বেশ কতগুলো সমস্যা রয়েছে -

১. এতে ইমেলারের সাথে স্পেল চেকার খুব টাইটলি কাপলড। এরা আলাদা আলাদাভাবে কাজ করতে পারে না। বাস্তব জগতের প্রত্যেকটি বস্তুই স্বাধীন। সুতরাং বাস্তব জগতের সঙ্গে সাদৃশ্য রইল না। 
২. আলাদা আলাদা স্পেল ফিক্সারের জন্য আলাদা ইমেইলারের প্রয়োজন হচ্ছে,এবং আলাদাভাবে কোড লিখতে হচ্ছে যাতে কোড ডুপ্লিকেশন হচ্ছে। 
৩. আমরা যদি দুটি অবজেক্টকে আলদা আলাদাভাবে টেস্ট করতে চাই, তা সম্ভব হয়ে উঠছে না। এখানে যদিও স্পেল চেকারকে আলাদা করে টেস্ট করা গেলেও, ইমেইলার টেস্ট করতে হলে স্পেল চেকারের অবজেক্ট প্রয়োজন। 
৪. এখানে দুইজন ডেভেলপার বা প্রোগ্রামার আলাদা আলাদাভাবে দুটি ক্লাস নিয়ে কাজ করতে পারবে না। 

এই উপরের সমস্যাগুলো সমাধান করার উপায় রয়েছে- 

নিচের কোডগুলো খেয়াল করুন- 

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public interface SpellFixer { 

    String fixSpelling(String text); 
} 

public class EnglishSpellChecker implements SpellFixer { 
    @Override 
    public String fixSpelling(String text) { 
        // business logic for english spell checker 

        return text; 
    } 
} 

public class BanglaSpellFixer implements SpellFixer { 
    public String fixSpelling(String text) { 
        // business logic for bangla spell fixer 

        return text; 
    } 
} 


public class Emailer { 
    private SpellFixer spellFixer; 

    public void setSpellFixer(SpellFixer spellFixer) { 
        this.spellFixer = spellFixer; 
    } 

    public void send(String text, String emailAddress) { 
        String fixedText = spellFixer.fixSpelling(text); 

        System.out.println("sending email to: " + emailAddress + " with following text: " + fixedText); 
    }  
} 

এখানে প্রথমে একটি ইন্টারেফস তৈরি করা হয়ছে। তারপর দুটি আলাদা ইমপ্লিমেন্টেশন লেখা হয়েছে।

পরবর্তীতে ইমেলার ক্লাসটিতে একটি সেটার মেথড দিয়ে স্পেল চেকারটি ইনজেক্ট করা হয়েছে। অর্থাৎ আমরা কোন স্পেল ফিক্সারটি ব্যবহার করবো তা নির্ভর করছে ইমেলার ইনস্ট্যানসিয়েট করার পর। 


1
2
3
4
5
6
7
8
        SpellFixer spellFixer = new EnglishSpellChecker();
        Emailer emailer = new Emailer();
        emailer.setSpellFixer(spellFixer);
        emailer.send("bla bla bla", "contact@bazlur.com");

        BanglaSpellFixer banglaSpellFixer = new BanglaSpellFixer();
        emailer.setSpellFixer(banglaSpellFixer);
        emailer.send("আমি বাংলার গান গাই", "contact@bazlur.com");

এতে করে অনেকগুলো সুবিধা হলো - 

১. স্পেল ফিক্সার একাধিক থাকলেও ইমেইলারে অবজেক্ট একই থাকছে। 
২. এখানে কোনো কোড ডুপ্লিকেশন নেই।
৩. আমি যখন ইমেইলার টেস্ট করবো তখন যদি কোনো স্পেল চেকার না থাকে,তাহলে একটি মক (Mock) স্পেল চেকার দিয়ে আমার কাজ করে নিতে পারবো। এতে টেস্টিং প্রক্রিয়া অনেক সহজ হয়ে যায়। 
৪. আলদা আলদাভাবে স্পেল চেকার ও ইমেলার তৈরি করা সম্ভব হয়ে যাচ্ছে। 

নিচে একটি টেস্টকোড দেওয়া হলো -

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class EmailerTest { 

    @Test 
    public void testSend() throws Exception { 
        SpellFixer spellFixer = Mockito.mock(SpellFixer.class); 

        String text = "hello world"; 

        when(spellFixer.fixSpelling(text)) 
                .thenReturn(text); 

        Emailer emailer = new Emailer(); 
        emailer.setSpellFixer(spellFixer); 

        emailer.send(text, "contact@bazlur.com"); 
    } 
}

এখানে টেস্টিং ফ্রেমওয়ার্ক JUnit ও Mockito ব্যবহার করা হয়েছে। উপরের টেস্ট কোডটি যদিও কোনো অর্থপূর্ণ টেস্ট করে না, কিন্তু বোঝার জন্য দেওয়া হয়েছে। এখানে SpellFixer ইন্টারফেস ব্যবহার না করে বরং একে মক কর হয়েছে। অর্থাৎ এই পদ্ধতি ব্যবহার করলে যেকোনো ক্লাসকে স্বাধীনভাবে টেস্ট করা যায় এবং টেস্টেবল কোড লেখা যায়। 

উপরের কোডটিতে সেটার ব্যবহার করে অবজেক্ট ইনজেক্ট করা হয়েছে। তবে যদি আমরা কোনো বিশেষ কন্টেইনার যেমন- Spring, Google Guice, picoContainer ইত্যাদি ব্যবহার করে প্রক্রিয়াটি আরও সহজ করে ফেলা যায়। 

1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Emailer { 
    @Autowired 
    private SpellFixer spellFixer; 

    public void send(String text, String emailAddress) { 
        String fixedText = spellFixer.fixSpelling(text); 

        System.out.println("sending email to: " + emailAddress + " with following text: " + fixedText); 
    } 
}


উপরের কোডটিতে শুধু একটি অ্যানোটেশন ব্যবহার করা হয়েছে। এই ইমেইলার ব্যবহার করতে হলে SpellFixer এর ইমপ্লিমেন্টেশনের কোনো ইনস্ট্যান্স নিউ অপারেটর ব্যবহার করে তৈরি করার প্রয়োজন নেই। এখানে স্প্রিং কন্টেইনারের ইনস্ট্যান্স তৈরি করে ইনজেক্ট করে দেয় যখন প্রয়োজন হয়। এতে করে কোডটি আগের থেকে অনেক সংক্ষিপ্ত হয়। 

এই প্রক্রিয়াকে ইনভার্শন অব কন্ট্রোল(Inversion of Control) বলা হয়। অর্থাৎ এটি ব্যবহার করে অবজেক্ট ইনজেক্ট করার কন্ট্রোলটি আমরা একটি কন্টেইনারক দিয়ে দেওয়া হয়। 

এখানে দুটি বিষয় লক্ষ্য করা যায় - 

১. কী করতে চাই
২. কখন করতে চাই

কী করতে চাইকে কখন করতে চাই থেকে আলাদা করে ফেলে আমরা একটি কন্টেইনারকে সেই দায়িত্ব দিয়ে দিতে পারি। কন্টেইনার সিন্ধান্ত নেবে কখন কোন অবজেক্ট ইনস্ট্যানসিয়েট করতে হবে । এই কন্ট্রোলকে আমাদের হাত থেকে কন্টেইনারকে দিয়ে দেওয়ার প্রক্রিয়াকে ইনভারর্সন অব কন্ট্র্রোল বলা হয়। 

Saturday, July 15, 2017

How to make coffee using Java

বলা হয়ে থাকে, প্রোগ্রামার হলো একটি মেশিন যা কফিকে কোডে রূপান্তর করতে পারে। এ থেকেই বোঝা যাচ্ছে কফি অত্যন্ত গুরুত্বপূর্ণ একটি পানীয়।

চলুন তাহলে দেখা যাক কীভাবে এই কফি তৈরি করা যায়?

জাভা দিয়ে কফি তৈরির জন্য প্রয়োজন একটি প্যাটার্ন। এর নাম ডেকোরেটর প্যাটার্ন।

ডেকোরেটর প্যাটার্নের মূল কথা হলো, ডাইনামিক্যালী একটি অবজেক্টে অতিরিক্ত বৈশিষ্ট্যাবলী যুক্ত করা। যেমন- একটি ছবির ফ্রেম। ছবিটি আমাদের মূল অবজেক্ট। এতে একটি ফ্রেম যুক্ত করে একে ডেকোরেট বা অলঙ্কৃত করা। ডেকোরেটার প্যাটার্নে শুরুতে একটি ইন্টারফেস তৈরি করা হয়। এতে একটি মেথড থাকে যা একটি বৈশিষ্ট্য যুক্ত করতে পারে। একটি কনক্রিট ক্লাস থাকে যা ইন্টারফেসটির ইমপ্লিমেন্টেশন। একটি ডেকোরেটর ক্লাস থাকে যাতে ইন্টারফেসটির একটি রেফারেন্স থাকে এবং এটিও ইন্টারফেসটিকে ইমপ্লিমেন্ট করে। এটি সাধরণত একটি অ্যাবস্ট্রাক্ট ক্লাস হয়। এরপর কতগুলো কনক্রিট অ্যাবস্ট্রাক্ট ক্লাস থাকে। একটি উদাহরণ দেওয়া যাক-


1
2
3
public interface Coffee {
    String getIngredient();
}

এর একটি কনক্রিট ক্লাস -


1
2
3
4
5
6
public class CoffeeBean implements Coffee {
    @Override
    public String getIngredient() {
        return "Coffee bean";
    }
}

এবার একটি ডেকোরেটর ক্লাস লেখা যাক -


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public abstract class CoffeeDecorator implements Coffee {
    private final Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public String addIngredient() {
        return coffee.getIngredient();
    }
}

এবার কিছু কনক্রিট ডেকোরেটর লেখা যাক-


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class SaltedCaramelFudge extends CoffeeDecorator {

    public SaltedCaramelFudge(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String addIngredient() {
        return super.getIngredient() + " + Salted caramel fudge";
    }
}
public class SweetenedMilk extends CoffeeDecorator {
    public SweetenedMilk(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String addIngredient() {
        return super.getIngredient() + " + Sweetened Milk";
    }
}
public class VanillaAlmondExtract extends CoffeeDecorator {
    public VanillaAlmondExtract(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String addIngredient() {
        return super.getIngredient() + " + Vanilla/almond extract";
    }
}
public class DarkCookieCrumb extends CoffeeDecorator {
    public DarkCookieCrumb(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String addIngredient() {
        return super.getIngredient() + " + Dark Cookie Crumb";
    }
}

এবার এগুলো দিয়ে কফি তৈরি করা যাক -


1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class CoffeeApp {

    public static void main(String[] args) {

        Coffee coffee = new VanillaAlmondExtract(new SaltedCaramelFudge(new SweetenedMilk(new CoffeeBean())));
        System.out.println(coffee.getIngredient());
    }
}
Output: 
Coffee bean + Sweetened Milk + Salted caramel fudge + Vanilla/almond extract

একটির কনস্ট্রাক্টরে আরেকটি পাস করে করে এভাবে আমরা ডেকোরেটর প্যাটার্ন ব্যবহার করে ডাইনামিক্যালী কফি তৈরি করতে পারি।

Saturday, July 1, 2017

জাভাতে toString() এর কাজ কী? (Use of toString() Method in java)

জাভাতে toString() এর কাজ কী?

কোনো জাভা অবজেক্টেকে স্ট্রিংয়ে রূপান্তর করতে চাইলে toString() মেথড কল করা হয়। এটি নানা কাজে বিশেষ করে ডিবাগিং কাজে ব্যবহার করা হয়। 

নিচের ক্লাসটি খেয়াল করুন-


1
2
3
4
5
6
7
8
9
public class Employee {
   private String name;
   private int age;

   public Example(String name, int age) {
      this.name = name;
      this.age = age;
   }
}

এবার একটি অবজেক্ট তৈরি করে toString()মেথড কল করা যাক। 


1
2
3
4
public static void main(String[] args) {
   Employee employee = new Employee("Rahim", 27);
   System.out.println(employee.toString());
}


এটিকে রান করলে -


যেহেতু Employee ক্লাসটিতে toString() মেথডটি ওভাররাইড করা হয়নি, তাই এটি Object ক্লাসের toString()মেথডটি কল হয় যা ক্লাস নামের সঙ্গে হ্যাশকোড যুক্ত করে রিটার্ন করেন। 

অর্থপূর্ণ কোনো কিছু রিটার্ন করতে হলে চলুন এটিকে ওভাররাইড করি।


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class Employee {
   private String name;
   private int age;

   public Employee(String name, int age) {
      this.name = name;
      this.age = age;
   }

   @Override
   public String toString() {
      
      return name + ": " + age;
   }

   public static void main(String[] args) {
      Employee employee = new Employee("Rahim", 27);
      System.out.println(employee.toString());
   }
}

এটিকে রান করলে আউটপুট পাওয়া যাবে -

Rahim: 27