ফ্যাসাদ প্যাটার্ন (Facade Pattern)


অনেক সময় এপ্লিকেশন ডেভেলপ করার সময় এমন সব সিনারিও আসে যে আমাদের একটি কাজ ঠিক ভাবে সম্পন্ন করার জন্য Interrelated এবং Interconnected অনেকগুলো অবজেক্ট এর দরকার হয় ।

এর ফলে কোড লিখার সময় আমাদের অনেক রকম সমস্যার সম্মুখীন হতে হয় । যেমন Interconnected class গুলো অথবা ফাংশন গুলো কল করার সময় আমরা ভুল করে আগে /পরে কল করে ফেলতে পারি ।
যেমন ধরুন আমরা ডাটাবেজ থেকে কিছু ডাটা ফেচ করে আমরা আমাদের ইউজার ইন্টারফেস এ দেখাতে চাই  । একটা class এর রেস্পন্সিবিলিটি হচ্ছে এপ্লিকেশনকে ডাটাবেজ এর সাথে কানেক্ট করা । এখন ডাটা ফেচ করে আনার জন্য সবার আগে আমাদের এই class টা অথবা এর কোনও ফাংশন কল করতে হবে । তারপর  অন্যান্য class ইউজ করে ধরুন আমরা বিজনেস লজিক ইমপ্লিমেন্ট করলাম । এখন কেউ যদি ভুলে class কল করার অর্ডার মেইনটেইন না করে তাহলে এপ্লিকেশন কাজই করবে না । যেমন কেউ যদি সবকাজ করার পরে / সব class কল করার পর ডাটাবেজের সাথে যে class টি কানেক্ট করে সেটিকে কল করে বসল 😛

তাহলে একটা বিধ্বংসী ব্যাপার হয়ে যাবে কিন্তু 🙂

এখানে কোডের মাধ্যমে সিম্পল উদাহরণ দেয়ার জন্য চলুন আমরা গাড়ি বানানোর প্রক্রিয়াটি দেখে নিই ।

গাড়ি বানানোর জন্য আমাদের প্রথমে লাগবে একটি গাড়ীর বডিঃ

Body class হচ্ছে এরকমঃ

    public class Body
    {
        public Body() { }

        public void AddBody(BodyType bodyType)
        {
            Console.WriteLine("{0} Body Added", Enum.GetName(typeof(BodyType), bodyType));
        }
    }

এখানে AddBody() এর ভীতর আমরা BodyType এর একটা Enum pass করেছি ।

আমাদের BodyType enum হচ্ছে এরকমঃ

    public enum BodyType
    {
        Sedan,
        Hatch,
        Suv
    }

গাড়ীর বডি বানানোর পর লাগবে আমাদের গাড়ীর ইঞ্জিন । ইঞ্জিন class টি এরকমঃ

    public class Engine
    {
        public Engine() { }

        public void AddEngine(int cyclinders)
        {
            Console.WriteLine("{0} Cylinder Engine Added", cyclinders.ToString());
        }
    }

AddEngine() মেথডের ভেতর দিয়ে কয়টি সিলিন্ডার দিয়ে আমরা ইঞ্জিনটি বানাবো তা বলে দেয়া হয়েছে ।

ইঞ্জিন বানানোর পর আমরা পর্যায়ক্রমে গাড়ীর সিট এবং চাকা বানাবো । এভাবেঃ

সিটঃ

    public class Seats
    {
        public void AddSeats(int num)
        {
            Console.WriteLine("{0} Seats Added", num.ToString());
        }
    }

চাকাঃ

    public class Wheels
    {
        public void AddWheels(int num)
        {
            Console.WriteLine("{0} Wheels Added", num.ToString());
        }
    }

এখন আমাদের ClientCode দেখে আসি ।

    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Started Making Car..............");
            Body body = new Body();
            body.AddBody(BodyType.Suv);
            Engine engine = new Engine();
            engine.AddEngine(4);
            Seats seats = new Seats();
            seats.AddSeats(4);
            Wheels wheels = new Wheels();
            wheels.AddWheels(4);
            Console.WriteLine("Ended Making Car................");
        }
    }

আমাদের গাড়ি বানানো হয়ে গেছে । সিম্পল উদাহরণের জন্য আমাদের কোডে class গুলোর মধ্যে কোনও Dependency নেই ।

কিন্তু যদি থাকতো তাহলে সমস্যা  হতো।

মনে করুন একটি ইকমার্স সাইটের জন্য আমরা একটা লাইব্রেরী লিখে ফেললাম যেখানে ভ্যালিড ইউজার হলে তাকে আমরা কিছু জিনিস কিনতে দিবো, আর ভ্যালিড ইউজার না হলে তাকে কিছু মেসেজ দেখাবো ।

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

এরকম ধ্বংসযজ্ঞ থেকে পরিত্রাণ পেতে সাহায্য করে আমাদের Façade প্যাটার্ন ।

Façade প্যাটার্ন আমাদের একটি সিম্পল ইন্টারফেস এর মাধ্যমে পুরো একটি সাবসিস্টেম কে রিপ্রেজেন্ট করতে সাহায্য করে ।

এখন আসুন আমরা আমাদের ClientCode Refactor করে Façade Pattern এর দিকে নিয়ে যাই ।

আমরা একটি ইন্টারফেস বানাই ICar নামে যার একটি মেথড থাকবে BuildCar()

এখন CarFacade নামে একটি class বানাই যে Icar কে ইমপ্লিমেন্ট করবে । BuildCar() এর ভেতর আমরা আমাদের সাবসিস্টেমের বিজনেস লজিক অনুযায়ী কল করব ।

আমাদের ICar ইন্টারফেস টা এরকমঃ

    public interface ICar
    {
        void BuildCar();
    }

আর আমাদের CarFacade এরকমঃ

    public class CarFacade : ICar
    {
        private readonly Body _body;
        private readonly Engine _engine;
        private readonly Seats _seats;
        private readonly Wheels _wheels;
        public CarFacade()
        {
            _body = new Body();
            _engine = new Engine();
            _seats = new Seats();
            _wheels = new Wheels();
        }
        public void BuildCar()
        {
            Console.WriteLine("Started Making Car..............");
            _body.AddBody(BodyType.Sedan);
            _engine.AddEngine(6);
            _seats.AddSeats(4);
            _wheels.AddWheels(4);
            Console.WriteLine("Ended Making Car................");
        }
    }

তাকে এখন আমাদের ClientCode এ রকম সিম্পলঃ

    public class Program
    {
        public static void Main(string[] args)
        {
            ICar car = new CarFacade();
            car.BuildCar();
        }
    }

আমরা আসলে একটা মাত্র ইন্টারফেসের মাধ্যমে পুরো গাড়ি বানানোর প্রক্রিয়াটা Hide করে ফেললাম ।
চিন্তা করে দেখুন  ইকমার্স সাইটের জন্য লাইব্রেরীটা এভাবে ডিজাইন করলে লাইব্রেরীটা যারা ইউজ করবে তাদের শুধু মাত্র Façade কল করলেই কাজ হয়ে যেত । কোন অবজেক্ট এর পর কোন অবজেক্ট বানাতে হবে , এদের ভেতর Interaction কেমন হবে এই ব্যাপারগুলো নিয়ে ডেভেলপারকে ভাবতেই হতোনা ।

শেষকথা:  অবজেক্ট অরিয়েন্টের ডিজাইনে Information Hiding একটি গুরুত্বপূর্ণ ব্যাপার । আরেকটি ব্যাপার হচ্ছে Principle of Least Knowledge।  এই দুটো বিষয় নিয়ে একটু গুগলে গুতোগুতি করলেই পেয়ে যাবেন আশাকরি । 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s