আপনি কি ল সিস্কো সাবস্টিটিউশন নীতিটি একটি ভাল সি # উদাহরণ দিয়ে ব্যাখ্যা করতে পারেন? [বন্ধ]


94

আপনি কি লিসকোব সাবস্টিটিউশন নীতিটি (SOLID এর 'এল') একটি ভাল সি # উদাহরণ দিয়ে ব্যাখ্যা করতে পারবেন যে নীতিটির সমস্ত দিককে সরলীকৃত উপায়ে আবৃত করা হয়েছে? যদি সত্যিই সম্ভব হয়।


9
সংক্ষেপে এটি সম্পর্কে চিন্তাভাবনার একটি সহজ উপায়: আমি যদি এলএসপি অনুসরণ করি তবে আমি আমার কোডের যে কোনও বস্তুকে একটি মক অবজেক্টের সাথে প্রতিস্থাপন করতে পারি এবং কলিং কোডের কোনও কিছুই পরিবর্তনের জন্য অ্যাকাউন্টে সামঞ্জস্য বা পরিবর্তন করতে হবে না। মক প্যাটার্ন দ্বারা টেস্টের জন্য এলএসপি একটি মৌলিক সমর্থন।
কিমোট

উত্তর:


128

(এই উত্তরটি 2013-05-13 এ আবার লেখা হয়েছে, মন্তব্যগুলির নীচে আলোচনাটি পড়ুন)

এলএসপি বেস ক্লাসের চুক্তি অনুসরণ করতে চলেছে।

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

এখানে এলএসপি লঙ্ঘনকারী শ্রেণীর কাঠামোর উদাহরণ রয়েছে:

public interface IDuck
{
   void Swim();
   // contract says that IsSwimming should be true if Swim has been called.
   bool IsSwimming { get; }
}

public class OrganicDuck : IDuck
{
   public void Swim()
   {
      //do something to swim
   }

   bool IsSwimming { get { /* return if the duck is swimming */ } }
}

public class ElectricDuck : IDuck
{
   bool _isSwimming;

   public void Swim()
   {
      if (!IsTurnedOn)
        return;

      _isSwimming = true;
      //swim logic            
   }

   bool IsSwimming { get { return _isSwimming; } }
}

এবং কলিং কোড

void MakeDuckSwim(IDuck duck)
{
    duck.Swim();
}

আপনি দেখতে পাচ্ছেন, হাঁসের দুটি উদাহরণ রয়েছে। একটি জৈব হাঁস এবং একটি বৈদ্যুতিক হাঁস। বৈদ্যুতিন হাঁসটি কেবল চালু থাকলেই সাঁতার কাটতে পারে। এটি এলএসপি নীতিটি ভঙ্গ করে যেহেতু সাঁতার কাটাতে সক্ষম হতে হবে IsSwimming( যেটিও চুক্তির অংশ) বেস ক্লাসের মতো সেট করা হবে না।

আপনি অবশ্যই এটির মতো কিছু করে সমাধান করতে পারেন

void MakeDuckSwim(IDuck duck)
{
    if (duck is ElectricDuck)
        ((ElectricDuck)duck).TurnOn();
    duck.Swim();
}

তবে এটি ওপেন / ক্লোজড নীতিটি ভঙ্গ করবে এবং সর্বত্র প্রয়োগ করতে হবে (এবং তবুও অস্থির কোড উত্পন্ন হয়)।

সঠিক সমাধানটি হ'ল Swimপদ্ধতিতে হাঁসটিকে স্বয়ংক্রিয়ভাবে চালু করা এবং এটি করে বৈদ্যুতিন হাঁসটিকে IDuckইন্টারফেসের দ্বারা নির্ধারিত ঠিক মতো আচরণ করা

হালনাগাদ

কেউ একটি মন্তব্য যোগ করেছেন এবং এটি সরান। এটির একটি বৈধ পয়েন্ট ছিল যা আমি সম্বোধন করতে চাই:

Swimপ্রকৃত বাস্তবায়ন ( ElectricDuck) এর সাথে কাজ করার সময় পদ্ধতির অভ্যন্তরে হাঁসকে ঘুরিয়ে দেওয়ার সমাধানের পার্শ্ব প্রতিক্রিয়া হতে পারে । তবে এটি একটি সুস্পষ্ট ইন্টারফেস বাস্তবায়ন ব্যবহার করে সমাধান করা যেতে পারে । imho সম্ভবত Swimএটি IDuckইন্টারফেসটি ব্যবহার করার সময় এটি সাঁতার কাটবে বলে আশা করা হচ্ছে যেহেতু এটি চালু না করে আপনি সমস্যা পেতে পারেন

আপডেট 2

আরও স্পষ্ট করতে কিছু অংশ পুনরায় চাপিয়েছেন।


4
@ জাগাফিন: উদাহরণটি সহজ এবং স্পষ্ট। তবে আপনি যে সমাধানটি প্রস্তাব করেছেন, প্রথমে: ওপেন-ক্লোজড নীতি ভেঙে দেয় এবং এটি চাচা বব এর সংজ্ঞা (তাঁর নিবন্ধের উপসংহার অংশটি দেখুন) এর সাথে খাপ খায় না যা লিখেছেন: "লিসকভ সাবস্টিটিউশন নীতিমালা (চুক্তি অনুসারে একেএ ডিজাইন) একটি গুরুত্বপূর্ণ বৈশিষ্ট্য ওপেন-ক্লোজড নীতি অনুসারে সমস্ত প্রোগ্রাম। " দেখুন: অবজেক্টমোয়ারস
আর্টিকেলস

4
সমাধানটি কীভাবে খোলা / বন্ধ হয়ে যায় তা আমি দেখতে পাচ্ছি না। আপনি যদি if duck is ElectricDuckঅংশটি উল্লেখ করছেন তবে আমার উত্তরটি আবার পড়ুন । আমি গত বৃহস্পতিবার
সলাইড

সত্যিকার অর্থে নয়, তবে আপনি কী দয়া করে নিজের উদাহরণটি পরিবর্তন করতে পারেন যাতে আপনি দুবার টাইপ-চেকিং না করেন? প্রচুর বিকাশকারী asকীওয়ার্ড সম্পর্কে অবগত নন , যা আসলে তাদের প্রচুর টাইপ-চেকিং থেকে বাঁচায়। আমি নিম্নলিখিতগুলির মতো কিছু ভাবছি:if var electricDuck = duck as ElectricDuck; if(electricDuck != null) electricDuck.TurnOn();
দর্শকদের

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

4
@ মিস্ত্রিমন: imho এলএসপি সবই আচরণগত নির্ভুলতার বিষয়ে। আয়তক্ষেত্র / বর্গক্ষেত্রের উদাহরণ সহ আপনি অন্যান্য সম্পত্তি সেট হওয়ার পার্শ্ব প্রতিক্রিয়া পাবেন। হাঁসের সাথে আপনি এর সাঁতার না পার্শ্ব প্রতিক্রিয়া পাবেন get এলএসপি:if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g., correctness).
জেগফিন

9

এলএসপি একটি ব্যবহারিক পদ্ধতির

আমি যেখানেই এলএসপির সি # উদাহরণ সন্ধান করেছি, লোকেরা কাল্পনিক ক্লাস এবং ইন্টারফেস ব্যবহার করেছে। আমি আমাদের সিস্টেমে একটিতে প্রয়োগ করেছি এমন এলএসপির ব্যবহারিক বাস্তবায়ন এখানে।

পরিস্থিতি: ধরুন আমাদের কাছে 3 টি ডাটাবেস রয়েছে (বন্ধকী গ্রাহকগণ, কারেন্ট অ্যাকাউন্টস গ্রাহক এবং সঞ্চয়ী অ্যাকাউন্ট গ্রাহক) যা গ্রাহকের ডেটা সরবরাহ করে এবং প্রদত্ত গ্রাহকের শেষ নামটির জন্য আমাদের গ্রাহকের বিবরণ প্রয়োজন। প্রদত্ত পদবি দেওয়া নামের পরিবর্তে আমরা সেই 3 টি ডাটাবেস থেকে 1 টিরও বেশি গ্রাহক বিশদ পেতে পারি।

বাস্তবায়ন:

ব্যবসায় মডেল স্তর:

public class Customer
{
    // customer detail properties...
}

ডেটা অ্যাক্সেস লেয়ার:

public interface IDataAccess
{
    Customer GetDetails(string lastName);
}

উপরে ইন্টারফেস বিমূর্ত শ্রেণি দ্বারা প্রয়োগ করা হয়

public abstract class BaseDataAccess : IDataAccess
{
    /// <summary> Enterprise library data block Database object. </summary>
    public Database Database;


    public Customer GetDetails(string lastName)
    {
        // use the database object to call the stored procedure to retrieve the customer details
    }
}

এই বিমূর্ত শ্রেণীর সমস্ত 3 ডাটাবেসের জন্য একটি সাধারণ পদ্ধতি "গেটডেটেলস" রয়েছে যা নীচে প্রদর্শিত প্রতিটি ডাটাবেস ক্লাস দ্বারা প্রসারিত

মর্টেজ গ্রাহক ডেটা অ্যাক্সেস:

public class MortgageCustomerDataAccess : BaseDataAccess
{
    public MortgageCustomerDataAccess(IDatabaseFactory factory)
    {
        this.Database = factory.GetMortgageCustomerDatabase();
    }
}

বর্তমান অ্যাকাউন্ট গ্রাহক ডেটা অ্যাক্সেস:

public class CurrentAccountCustomerDataAccess : BaseDataAccess
{
    public CurrentAccountCustomerDataAccess(IDatabaseFactory factory)
    {
        this.Database = factory.GetCurrentAccountCustomerDatabase();
    }
}

অ্যাকাউন্ট গ্রাহক ডেটা অ্যাক্সেস সঞ্চয় করে:

public class SavingsAccountCustomerDataAccess : BaseDataAccess
{
    public SavingsAccountCustomerDataAccess(IDatabaseFactory factory)
    {
        this.Database = factory.GetSavingsAccountCustomerDatabase();
    }
}

এই 3 ডেটা অ্যাক্সেস ক্লাসগুলি সেট হয়ে গেলে, এখন আমরা ক্লায়েন্টের দিকে আমাদের দৃষ্টি আকর্ষণ করি। বিজনেস লেয়ারে আমাদের কাস্টমার সার্ভিস ম্যানেজার ক্লাস থাকে যা গ্রাহকদের বিবরণটিকে তার ক্লায়েন্টগুলিতে ফিরিয়ে দেয়।

ব্যবসায় স্তর:

public class CustomerServiceManager : ICustomerServiceManager, BaseServiceManager
{
   public IEnumerable<Customer> GetCustomerDetails(string lastName)
   {
        IEnumerable<IDataAccess> dataAccess = new List<IDataAccess>()
        {
            new MortgageCustomerDataAccess(new DatabaseFactory()), 
            new CurrentAccountCustomerDataAccess(new DatabaseFactory()),
            new SavingsAccountCustomerDataAccess(new DatabaseFactory())
        };

        IList<Customer> customers = new List<Customer>();

       foreach (IDataAccess nextDataAccess in dataAccess)
       {
            Customer customerDetail = nextDataAccess.GetDetails(lastName);
            customers.Add(customerDetail);
       }

        return customers;
   }
}

ইতিমধ্যে এটি এখন জটিল হয়ে যাওয়ায় নির্ভরযোগ্যতা ইনজেকশনটি এটিকে সহজ রাখার জন্য দেখায় নি।

এখন যদি আমাদের কাছে নতুন গ্রাহকের বিশদ ডেটাবেস থাকে তবে আমরা কেবলমাত্র একটি নতুন শ্রেণি যুক্ত করতে পারি যা বেসডেটাঅ্যাক্সেস প্রসারিত করে এবং এটির ডাটাবেস অবজেক্ট সরবরাহ করে।

অবশ্যই আমাদের অংশগ্রহণকারী সকল ডেটাবেজে অভিন্ন স্টোরেজ পদ্ধতিগুলি দরকার।

শেষ CustomerServiceManagerঅবধি, ক্লাসের ক্লায়েন্ট কেবলমাত্র getCustomerDetails পদ্ধতি কল করবে, শেষ নামটি পাস করবে এবং কীভাবে এবং কোথা থেকে ডেটা আসছে তা নিয়ে চিন্তা করা উচিত নয়।

আশা করি এটি আপনাকে এলএসপি বোঝার জন্য ব্যবহারিক পদ্ধতির সুযোগ দেবে।


4
এটি কীভাবে এলএসপির উদাহরণ?
somegeek

4
আমি এর মধ্যেও এলএসপির উদাহরণ দেখতে পাচ্ছি না ... কেন এটি এত বেশি উপার্জন করে?
স্টাভনভ

4
@ রোশনঘাংগড় আইডিটাএ্যাক্সেসে 3 টি কংক্রিট বাস্তবায়ন রয়েছে যা ব্যবসায় স্তরতে প্রতিস্থাপিত হতে পারে।
ইয়াবার মুর্তজা

4
@ ইয়াওয়ারমুর্তজা আপনি যা উদ্ধৃত করেছেন তার উদাহরণ হ'ল কৌশল রীতিটির বাস্তবায়ন এটি it আপনি কী দয়া করে পরিষ্কার করতে পারেন এটি কোথায় এলএসপিকে ভঙ্গ করছে এবং কীভাবে আপনি এলএসপির লঙ্ঘন সমাধান করবেন
যোগেশ

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

0

লিসকভ সাবস্টিটিউট নীতি প্রয়োগ করার কোড এখানে the

public abstract class Fruit
{
    public abstract string GetColor();
}

public class Orange : Fruit
{
    public override string GetColor()
    {
        return "Orange Color";
    }
}

public class Apple : Fruit
{
    public override string GetColor()
    {
        return "Red color";
    }
}

class Program
{
    static void Main(string[] args)
    {
        Fruit fruit = new Orange();

        Console.WriteLine(fruit.GetColor());

        fruit = new Apple();

        Console.WriteLine(fruit.GetColor());
    }
}

এলএসভির বিবৃতিতে বলা হয়েছে: "উত্পন্ন ক্লাসগুলি তাদের বেস ক্লাসগুলির জন্য (বা ইন্টারফেস) পরিবর্তনের যোগ্য হওয়া উচিত" এবং "বেস ক্লাসগুলির (বা ইন্টারফেস) উল্লেখগুলি পদ্ধতিগুলি না জেনে বা বিবরণ না জেনে উদ্ভূত শ্রেণির পদ্ধতি ব্যবহার করতে সক্ষম হতে হবে "

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.