লিসকভ সাবস্টিটিউশন নীতিমালার উদাহরণ কী?


908

শুনেছি লিসকভ সাবস্টিটিউশন প্রিন্সিপাল (এলএসপি) অবজেক্ট অরিয়েন্টেড ডিজাইনের একটি মৌলিক নীতি। এটি কী এবং এর ব্যবহারের কয়েকটি উদাহরণ কী?


এলএসপি আনুগত্য এবং লঙ্ঘনের আরও উদাহরণ এখানে
স্টুয়ার্টলসি

1
এই প্রশ্নের অসীম অনেক ভাল উত্তর আছে এবং তাই খুব বিস্তৃত
রায়েদওয়াল্ড

উত্তর:


891

এলএসপি চিত্রিত করার একটি দুর্দান্ত উদাহরণ (আমি সম্প্রতি পডকাস্টে আঙ্কেল বব দ্বারা প্রদত্ত) এটি ছিল যে কখনও কখনও প্রাকৃতিক ভাষায় যে শব্দটি ডান মনে হয় সেটি কোডটিতে বেশ কার্যকর হয় না।

গণিতে, SquareRectangle। আসলে এটি একটি আয়তক্ষেত্রের বিশেষত্ব special "এটি একটি" আপনাকে উত্তরাধিকারের সাথে মডেল করতে চায় makes তবে কোডে যদি আপনি Squareউদ্ভূত হন Rectangle, তবে আপনি যেখান থেকে Squareআশা করেন তা একটি ব্যবহারযোগ্য হবে Rectangle। এটি কিছু অদ্ভুত আচরণ করে তোলে।

আপনার বেস ক্লাসে আপনার পদ্ধতি SetWidthএবং SetHeightপদ্ধতিগুলি কল্পনা করুন Rectangle; এটি পুরোপুরি যৌক্তিক বলে মনে হয়। তবে যদি আপনার Rectangleউল্লেখকে একটি তীক্ষ্ন Square, তারপর SetWidthএবং SetHeightঅর্থে দেখা যায় না কারণ এক সেটিং জন এটি মেলে পরিবর্তন হবে। এই ক্ষেত্রে Squareসঙ্গে Liskov উপকল্পন টেস্ট ব্যর্থ Rectangleএবং থাকার বিমূর্ততা Squareথেকে উত্তরাধিকারী Rectangleএকটি খারাপ নেই।

এখানে চিত্র বর্ণনা লিখুন

আপনার সমস্ত মূল্যবান সলিড নীতি মোটিভেশনাল পোস্টারগুলি পরীক্ষা করা উচিত ।


19
@ মি-স্ট্রিপ যদি এটির পরিবর্তনযোগ্য আয়তক্ষেত্র যেমন সেটউইথথ এবং সেটহাইটের পরিবর্তে, আমাদের পরিবর্তে গেটউইথ এবং গেটহাইট পদ্ধতি রয়েছে?
পেসারিয়ার

139
গল্পের নৈতিকতা: বৈশিষ্ট্যগুলিতে নয় এমন আচরণের ভিত্তিতে আপনার ক্লাসগুলির মডেল করুন; বৈশিষ্ট্যের ভিত্তিতে আপনার ডেটা মডেল করুন এবং আচরণের ভিত্তিতে নয়। যদি এটি হাঁসের মতো আচরণ করে তবে এটি অবশ্যই একটি পাখি।
Sklivvz

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

62
@ পেসারিয়র যদি তা পরিবর্তনযোগ্য না হয় তবে তাতে কোনও সমস্যা নেই। এখানে আসল বিষয়টি হ'ল আমরা আয়তক্ষেত্রগুলিকে মডেলিং করছি না, বরং "পুনর্নির্মাণযোগ্য আয়তক্ষেত্র", অর্থাৎ, আয়তক্ষেত্রগুলি যার প্রস্থ বা উচ্চতা তৈরি হওয়ার পরে সংশোধন করা যেতে পারে (এবং আমরা এখনও এটি একই বস্তু হিসাবে বিবেচনা করি)। আমরা যদি এভাবে আয়তক্ষেত্রের শ্রেণীর দিকে নজর রাখি তবে এটি স্পষ্ট হয় যে একটি বর্গক্ষেত্রটি "পুনঃসারণযোগ্য আয়তক্ষেত্র" নয়, কারণ একটি বর্গাকারটি পুনরায় আকার দেওয়া যায় না এবং এখনও একটি বর্গ হতে পারে (সাধারণভাবে)। গাণিতিকভাবে, আমরা সমস্যাটি দেখি না কারণ পরিব্যক্তি এমনকি গাণিতিক প্রসঙ্গে বোঝায় না।
asmeurer

14
নীতিটি সম্পর্কে আমার একটি প্রশ্ন আছে। কেন সমস্যা হবে যদি Square.setWidth(int width)ভালো বাস্তবায়িত হয়েছে: this.width = width; this.height = width;? এই ক্ষেত্রে এটি গ্যারান্টিযুক্ত যে প্রস্থটি উচ্চতার সমান।
এমসি সম্রাট

487

লিসকভ সাবস্টিটিউশন নীতি (এলএসপি, ) অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিংয়ের একটি ধারণা যা বলে:

বেস ক্লাসে পয়েন্টার বা রেফারেন্স ব্যবহার করে এমন ফাংশনগুলি অজান্তেই উত্পন্ন ক্লাসের অবজেক্টগুলি ব্যবহার করতে সক্ষম হতে হবে।

তার হৃদয়ে এলএসপি ইন্টারফেস এবং চুক্তিগুলি সম্পর্কে পাশাপাশি কোনও শ্রেণি কখন বাড়ানো উচিত তা কীভাবে সিদ্ধান্ত নেবে সে সম্পর্কে আপনার লক্ষ্য অর্জনের জন্য রচনা সম্পর্কিত আরও কৌশল ব্যবহার করুন।

এই পয়েন্টটি চিত্রিত করার জন্য আমি সবচেয়ে কার্যকর উপায়টি হেড ফার্স্ট ওওএ এবং ডি-তে ছিল । তারা কৌশল গেমগুলির জন্য একটি কাঠামো তৈরির জন্য একটি প্রকল্পে আপনি বিকাশকারী যেখানে একটি দৃশ্য উপস্থাপন করেন।

তারা এমন একটি শ্রেণি উপস্থাপন করে যা এমন বোর্ডের প্রতিনিধিত্ব করে যা দেখতে দেখতে:

ক্লাস ডায়াগ্রাম

দ্বি-মাত্রিক অ্যারেটিতে টাইলের অবস্থান নির্ধারণের জন্য সমস্ত পদ্ধতি এক্স এবং ওয়াই সমন্বয়কে পরামিতি হিসাবে গ্রহণ করে Tiles। এটি কোনও গেম ডেভেলপারকে গেমের সময়কালে বোর্ডে ইউনিট পরিচালনা করতে দেয়।

বইটি প্রয়োজনীয়তাগুলি পরিবর্তন করতে গিয়ে বলেছে যে গেমের ফ্রেমের কাজের সাথে ফ্লাইট রয়েছে এমন গেমগুলিকে সামঞ্জস্য করতে 3 ডি গেম বোর্ডকেও সমর্থন করতে হবে। সুতরাং একটি ThreeDBoardশ্রেণি প্রবর্তিত হয় যা প্রসারিত হয় Board

প্রথম নজরে এটি একটি ভাল সিদ্ধান্ত বলে মনে হচ্ছে। Boardউভয় Heightএবং Widthবৈশিষ্ট্য ThreeDBoardসরবরাহ করে এবং Z অক্ষ সরবরাহ করে।

এটা কোথায় প্রায় ভেঙে পড়েছে যখন আপনি সব অপরের থেকে উত্তরাধিকারসূত্রে সদস্যদের তাকান হয় Board। জন্য পদ্ধতি AddUnit, GetTile, GetUnitsইত্যাদি, সমস্ত উভয় X এবং Y পরামিতি গ্রহণ Boardবর্গ কিন্তু ThreeDBoardসেইসাথে একটি টু Z প্যারামিটার প্রয়োজন।

সুতরাং আপনাকে অবশ্যই জেড প্যারামিটার দিয়ে আবার সেই পদ্ধতিগুলি প্রয়োগ করতে হবে। জেড প্যারামিটারটির Boardক্লাসের কোনও প্রসঙ্গ নেই এবং বর্গ থেকে উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিগুলি Boardতাদের অর্থ হারিয়ে ফেলে। ক্লাসটিকে ThreeDBoardতার বেস শ্রেণি হিসাবে ব্যবহার করার চেষ্টা করার কোডের একটি ইউনিট Boardভাগ্যের বাইরে চলে যাবে।

হতে পারে আমাদের অন্য পদ্ধতির সন্ধান করা উচিত। ব্যাপ্ত পরিবর্তে Board, ThreeDBoardগঠিত হবে Boardবস্তু। Boardজেড অক্ষের প্রতি ইউনিট প্রতি এক বস্তু।

এটি আমাদের এনক্যাপসুলেশন এবং পুনঃব্যবহারের মতো ভাল অবজেক্ট ওরিয়েন্টেড নীতিগুলি ব্যবহার করতে দেয় এবং এলএসপি লঙ্ঘন করে না।


10
অনুরূপ তবে সহজ উদাহরণের জন্য উইকিপিডিয়ায় সার্কেল-উপবৃত্ত সমস্যাও দেখুন ।
ব্রায়ান

@ নটমাইসেলফের অনুরোধ: "আমি মনে করি যে উদাহরণটি কেবল এটা প্রমাণ করার জন্য যে বোর্ডের কাছ থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হওয়া থ্রিডিবোর্ডের প্রসঙ্গে বোঝায় না এবং পদ্ধতিটির স্বাক্ষরগুলির সমস্ত জেড অক্ষের সাথে অর্থহীন" "
কনটাঙ্গো

1
সুতরাং আমরা যদি একটি শিশু শ্রেণিতে অন্য পদ্ধতি যুক্ত করি তবে পিতামাতার সমস্ত কার্যকারিতা এখনও শিশু শ্রেণিতে বোঝায় এটি কি এলএসপি ভেঙে দেবে? যেহেতু একদিকে আমরা শিশুটিকে কিছুটা ব্যবহার করার জন্য ইন্টারফেসটি পরিবর্তন করেছি অন্যদিকে যদি আমরা শিশুটিকে পিতামাতা হিসাবে রেখে দিই যে কোনও পিতা-মাতার সূক্ষ্ম কাজ করবে বলে আশা করে code
নিকোলে কোন্ড্রাটয়েভ

5
এটি লিসকোবিরোধী উদাহরণ is লিসকভ আমাদের স্কোয়ার থেকে আয়তক্ষেত্র আঁকতে তৈরি করে। কম-প্যারামিটার-ক্লাস থেকে আরও পরামিতি-শ্রেণি। এবং আপনি সুন্দরভাবে দেখিয়েছেন যে এটি খারাপ। উত্তর হিসাবে চিহ্নিত করা এবং লিসকোভ প্রশ্নের জন্য অ্যান্টি-লিসকোভ উত্তরটি 200 বার উপস্থাপন করা সত্যিই একটি ভাল রসিকতা। লিসকভের নীতিটি কি সত্যই মিথ্যা?
গাংনাস

3
উত্তরাধিকারের কাজটি ভুল পথে দেখেছি। এখানে একটি উদাহরণ। বেস ক্লাসটি থ্রিডিবোর্ড এবং উত্পন্ন ক্লাস বোর্ড হতে হবে। বোর্ডের এখনও ম্যাক্স (জেড) = মিন (জেড) = 1
পলাস্ট্রিউস

168

সাবস্টিটিউটেবিলিটি হ'ল অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিংয়ে একটি নীতি যা উল্লেখ করে যে একটি কম্পিউটার প্রোগ্রামে, যদি এস টি-এর একটি উপপ্রকার হয়, তবে টাইপ টি-এর বস্তুগুলি এস টাইপের বস্তুর সাথে প্রতিস্থাপন করা যেতে পারে type

আসুন জাভাতে একটি সাধারণ উদাহরণটি করি:

খারাপ উদাহরণ

public class Bird{
    public void fly(){}
}
public class Duck extends Bird{}

হাঁসটি উড়ে যেতে পারে কারণ এটি একটি পাখি, তবে এটি কী:

public class Ostrich extends Bird{}

অস্ট্রিচ একটি পাখি, তবে এটি উড়তে পারে না, অস্ট্রিচ শ্রেণি পাখি শ্রেণীর একটি উপ-প্রকার, তবে এটি উড়ানের পদ্ধতিটি ব্যবহার করতে পারে না, তার মানে আমরা এলএসপি নীতিটি ভঙ্গ করছি।

ভালো উদাহরণ

public class Bird{
}
public class FlyingBirds extends Bird{
    public void fly(){}
}
public class Duck extends FlyingBirds{}
public class Ostrich extends Bird{} 

3
দুর্দান্ত উদাহরণ, তবে ক্লায়েন্ট থাকলে আপনি কী করবেন Bird bird। ফ্লাই ব্যবহার করতে আপনাকে ফ্লাইংবার্ডসে বস্তুটি ফেলে দিতে হবে, যা ভাল না?
মুডি

16
না। যদি ক্লায়েন্টের থাকে তবে এর Bird birdঅর্থ এটি ব্যবহার করতে পারবেন না fly()। এটাই. পাস করার Duckফলে এই সত্যটি পরিবর্তন হয় না। যদি ক্লায়েন্টটি থাকে FlyingBirds bird, তবে এটি পাস হয়ে গেলেও Duckএটি সর্বদা একইভাবে কাজ করা উচিত।
স্টিভ চ্যামিলার্ড

9
এটিও ইন্টারফেস বিভাজনের জন্য একটি ভাল উদাহরণ হিসাবে কাজ করবে না?
সাহার্স

দুর্দান্ত উদাহরণ ধন্যবাদ ম্যান
আবদুলহাদি আবদো

6
ইন্টারফেস 'ফ্লাইয়েবল' কীভাবে ব্যবহার করা যায় (এর চেয়ে ভাল নামটি ভাবতে পারে না)। এইভাবে আমরা এই কঠোর শ্রেণিবিন্যাসের জন্য নিজেকে প্রতিশ্রুতিবদ্ধ করি না .. যদি না আমরা জানি যে সত্যই এটির প্রয়োজন নেই।
তৃতীয়াংশ

132

এলএসপি উদ্বেগীদের উদ্বেগ করে।

ক্লাসিক উদাহরণটি নিম্নলিখিত সিউডো-কোড ঘোষণার দ্বারা দেওয়া হয়েছে (বাস্তবায়ন বাদ দেওয়া হয়েছে):

class Rectangle {
    int getHeight()
    void setHeight(int value)
    int getWidth()
    void setWidth(int value)
}

class Square : Rectangle { }

ইন্টারফেস মেলে যদিও এখন আমাদের একটি সমস্যা আছে। কারণটি হ'ল আমরা চৌকো এবং আয়তক্ষেত্রের গাণিতিক সংজ্ঞা থেকে উদ্ভূত আক্রমণকারীদের লঙ্ঘন করেছি। গেটার্স এবং সেটাররা যেভাবে কাজ করে, Rectangleতাদের নীচের আক্রমণকারীটিকে সন্তুষ্ট করা উচিত:

void invariant(Rectangle r) {
    r.setHeight(200)
    r.setWidth(100)
    assert(r.getHeight() == 200 and r.getWidth() == 100)
}

তবে, এই আক্রমণকারীকে অবশ্যই সঠিক প্রয়োগের দ্বারা লঙ্ঘন করতে হবে Square, সুতরাং এটি কোনও বৈধ বিকল্প নয় Rectangle


35
এবং সেইজন্য আমরা আসলে মডেল করতে চাইলে যে কোনও কিছুকে "OO" ব্যবহার করতে অসুবিধা হয়।
ড্রিপজ্জা

9
@ ড্রিপিজা: একেবারে। তবে, দুটি জিনিস। প্রথমত, এই ধরনের সম্পর্কগুলি এখনও অসম্পূর্ণভাবে বা আরও জটিল চারপাশ ব্যবহার করেও OOP এ মডেল করা যেতে পারে (আপনার সমস্যা অনুসারে যাহা চয়ন করুন)। দ্বিতীয়ত, এর চেয়ে ভাল বিকল্প আর নেই। অন্যান্য ম্যাপিং / মডেলিংয়ের একই বা একই রকম সমস্যা রয়েছে। ;-)
কনরাড রুডল্ফ

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

7
ওওপি অর্থ আচরণ নয় মডেল আচরণের জন্য model আপনার ক্লাসগুলি এলএসপি লঙ্ঘনের আগেও এনক্যাপসুলেশন লঙ্ঘন করে।
Sklivvz

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

77

লিসকো সাবস্টিটিউশন নীতিতে রবার্ট মার্টিনের একটি দুর্দান্ত কাগজ রয়েছে । এটি সূক্ষ্ম এবং না-সূক্ষ্ম উপায়গুলি নিয়ে আলোচনা করে যাতে নীতির লঙ্ঘন হতে পারে।

কাগজের কিছু প্রাসঙ্গিক অংশ (দ্বিতীয় উদাহরণটি ভারীভাবে ঘনীভূত রয়েছে তা নোট করুন):

এলএসপি লঙ্ঘনের একটি সহজ উদাহরণ

এই নীতিটির সবচেয়ে লঙ্ঘনকারী লঙ্ঘনগুলির মধ্যে একটি হ'ল একটি অবজেক্টের ধরণের উপর ভিত্তি করে কোনও ফাংশন নির্বাচন করতে সি ++ রান-টাইম টাইপ ইনফরমেশন (আরটিটিআই) ব্যবহার। অর্থাৎ,

void DrawShape(const Shape& s)
{
  if (typeid(s) == typeid(Square))
    DrawSquare(static_cast<Square&>(s)); 
  else if (typeid(s) == typeid(Circle))
    DrawCircle(static_cast<Circle&>(s));
}

স্পষ্টতই DrawShapeফাংশনটি খারাপভাবে গঠিত হয়। এটি অবশ্যই Shapeবর্গের প্রতিটি সম্ভাব্য ডেরাইভেটিভ সম্পর্কে জানতে হবে এবং যখনই নতুন ডেরিভেটিভ Shapeতৈরি করা হবে তখন এটি অবশ্যই পরিবর্তন করা উচিত । প্রকৃতপক্ষে, অনেকে এই ফাংশনটির কাঠামোটিকে অরিজেন্ট ওরিয়েন্টেড ডিজাইনের জন্য অ্যানথেমা হিসাবে দেখেন।

স্কোয়ার এবং আয়তক্ষেত্র, আরও সূক্ষ্ম লঙ্ঘন।

তবে এলএসপি লঙ্ঘনের আরও অনেক সূক্ষ্ম ও উপায় রয়েছে। Rectangleক্লাসটি নীচে বর্ণিত হিসাবে ব্যবহার করে এমন একটি অ্যাপ্লিকেশন বিবেচনা করুন :

class Rectangle
{
  public:
    void SetWidth(double w) {itsWidth=w;}
    void SetHeight(double h) {itsHeight=w;}
    double GetHeight() const {return itsHeight;}
    double GetWidth() const {return itsWidth;}
  private:
    double itsWidth;
    double itsHeight;
};

[...] কল্পনা করুন যে একদিন ব্যবহারকারীরা আয়তক্ষেত্রগুলি ছাড়াও স্কোয়ারগুলি ব্যবহার করার দক্ষতার দাবি জানান। [...]

স্পষ্টতই, একটি বর্গক্ষেত্রটি সমস্ত সাধারণ অভিপ্রায় এবং উদ্দেশ্যগুলির জন্য একটি আয়তক্ষেত্র। আইএসএ সম্পর্ক যেহেতু ধরে রেখেছে তাই Square ক্লাসটি উত্পন্ন হিসাবে মডেল করা যৌক্তিক Rectangle। [...]

SquareSetWidthএবং SetHeightফাংশন উত্তরাধিকারী হবে । এই ফাংশনগুলি একটি এর জন্য একেবারে অনুপযুক্ত Square, যেহেতু একটি বর্গের প্রস্থ এবং উচ্চতা অভিন্ন। এটি একটি উল্লেখযোগ্য সূত্র হওয়া উচিত যা ডিজাইনে সমস্যা রয়েছে। যাইহোক, সমস্যার পাশ কাটাবার একটি উপায় রয়েছে। আমরা ওভাররাইড করতে পারি SetWidthএবং SetHeight[...]

তবে নিম্নলিখিত ফাংশনটি বিবেচনা করুন:

void f(Rectangle& r)
{
  r.SetWidth(32); // calls Rectangle::SetWidth
}

আমরা যদি Squareএই ফাংশনে কোনও অবজেক্টের রেফারেন্সটি পাস করি তবে Squareঅবজেক্টটি দূষিত হবে কারণ উচ্চতা পরিবর্তন হবে না। এটি এলএসপির স্পষ্ট লঙ্ঘন is ফাংশনটি তার যুক্তিগুলির ডেরাইভেটিভগুলির জন্য কাজ করে না।

[...]


14
দেরি হয়ে গেছে, তবে আমি ভেবেছিলাম এটি এই কাগজের একটি আকর্ষণীয় উক্তি: Now the rule for the preconditions and postconditions for derivatives, as stated by Meyer is: ...when redefining a routine [in a derivative], you may only replace its precondition by a weaker one, and its postcondition by a stronger one. যদি কোনও শিশু-শ্রেণির প্রাক-শর্তটি পিতামাতার শ্রেণির প্রাক-শর্তের চেয়ে শক্তিশালী হয় তবে আপনি প্রাক-শর্তটি লঙ্ঘন না করে কোনও সন্তানের কোনও পিতা-মাতার স্থান পরিবর্তন করতে পারবেন না। অতএব এলএসপি।
ব্যবহারকারী 2023861

@ user2023861 আপনি পুরোপুরি ঠিক বলেছেন। আমি এর উপর ভিত্তি করে একটি উত্তর লিখব।
inf3rno

40

এলএসপি প্রয়োজনীয় যেখানে কিছু কোড মনে করে যে এটি কোনও প্রকারের Tপদ্ধতিগুলি কল করছে এবং অজান্তেই কোনও প্রকারের পদ্ধতিগুলিকে কল করতে পারে S, যেখানে S extends T(যেমন Sউত্তরাধিকার সূত্রে প্রাপ্ত, সুপারটাইপের একটি উপ-প্রকার T)।

উদাহরণস্বরূপ, এটি ঘটে যখন টাইপের একটি ইনপুট প্যারামিটার সহ একটি ফাংশন T, যাকে টাইপের আর্গুমেন্ট মান সহ বলা হয় (অর্থাত্ আহ্বান করা হয়) S। বা, যেখানে প্রকারের সনাক্তকারীকে টাইপের Tমান নির্ধারিত করা হয় S

val id : T = new S() // id thinks it's a T, but is a S

এলএসপিতে প্রকারের T(যেমন, Rectangle) পদ্ধতিগুলির জন্য প্রত্যাশা (অর্থাত্ আক্রমণকারীদের) প্রয়োজন হয় , পরিবর্তে টাইপ S(যেমন Square) এর পদ্ধতিগুলি কল করার সময় লঙ্ঘন করা হবে না।

val rect : Rectangle = new Square(5) // thinks it's a Rectangle, but is a Square
val rect2 : Rectangle = rect.setWidth(10) // height is 10, LSP violation

এমনকি অপরিবর্তনীয় ক্ষেত্রগুলির সাথে একটি ধরণের এখনও অদলপ্রদর্শন রয়েছে , যেমন অপরিবর্তনীয় আয়তক্ষেত্রাকার সেটারগুলি মাত্রাগুলি স্বাধীনভাবে পরিবর্তিত হওয়ার প্রত্যাশা করে , তবে অপরিবর্তনীয় স্কয়ার সেটারগুলি এই প্রত্যাশা লঙ্ঘন করে।

class Rectangle( val width : Int, val height : Int )
{
   def setWidth( w : Int ) = new Rectangle(w, height)
   def setHeight( h : Int ) = new Rectangle(width, h)
}

class Square( val side : Int ) extends Rectangle(side, side)
{
   override def setWidth( s : Int ) = new Square(s)
   override def setHeight( s : Int ) = new Square(s)
}

এলএসপির প্রয়োজন যে Sসাব টাইপের প্রতিটি পদ্ধতিতে বিচ্ছিন্ন ইনপুট প্যারামিটার (গুলি) এবং কোভেরিয়েন্ট আউটপুট থাকতে হবে।

কনট্রাভেরিয়েন্ট মানে বৈকল্পিক উত্তরাধিকারের দিকের বিপরীতে, অর্থাৎ Siউপপ্রকারের প্রতিটি পদ্ধতির প্রতিটি ইনপুট প্যারামিটারের ধরণের বিপরীত Sহতে হবে, সুপারটাইপেরTi অনুরূপ পদ্ধতির সংশ্লিষ্ট ইনপুট প্যারামিটারের ধরণের একই বা একটি সুপারটাইপ হতে হবে T

কোভারিয়েন্স বলতে বোঝা যায় যে বৈকল্পিকটি উত্তরাধিকারের একই দিকের, অর্থাৎ প্রকারের Soপ্রতিটি পদ্ধতির আউটপুটের ধরণ S, একই রকমের সুপারটাইপের অনুরূপ পদ্ধতির সম্পর্কিত আউটপুটের ধরণের একই বা একটি উপপ্রকার হতে হবে ।ToT

এটি কারণ যদি কলার মনে করে যে এটির একটি প্রকার রয়েছে T, মনে করে এটি কোনও পদ্ধতি কল করছে T, তবে এটি আর্গুমেন্ট সরবরাহ করে Tiএবং টাইপটিকে আউটপুট বরাদ্দ করে To। যখন এটি প্রকৃতপক্ষে সম্পর্কিত পদ্ধতিটিকে কল করছে S, তারপরে প্রতিটি Tiইনপুট আর্গুমেন্ট একটি Siইনপুট প্যারামিটারের Soজন্য বরাদ্দ করা হয় এবং আউটপুট টাইপকে নির্ধারিত হয় To। সুতরাং যদি Siএটির তুলনামূলক বিস্ফোরণ না হয় Ti, তবে একটি উপ- Xiটাইপ - যা Siনির্ধারিত হবে তার একটি উপ-প্রকার নয় Ti

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

অতিরিক্তভাবে, প্রতিটি ইনপুট প্যারামিটার বা আউটপুট যাতে ফাংশনের ধরণ থাকে তার জন্য প্রয়োজনীয় বৈচিত্র্য দিকটি বিপরীত করা হয়। এই বিধি পুনরাবৃত্তির সাথে প্রয়োগ করা হয়।


আক্রমণকারীদের গণনা করা যায় সেখানে সাব টাইপিং উপযুক্ত

কীভাবে আক্রমণকারীদের মডেল করা যায় সে সম্পর্কে অনেক চলমান গবেষণা চলছে, যাতে তারা সংকলক দ্বারা প্রয়োগ করা হয়।

টাইপস্টেট (পৃষ্ঠা 3 দেখুন) টাইপ করার জন্য রাষ্ট্র আক্রমণকারীদের অরথোগোনাল ঘোষণা করে এবং প্রয়োগ করে। বিকল্পভাবে, আগ্রাসনগুলিকে জোর দিয়ে বিভিন্ন ধরণের রূপান্তর করে প্রয়োগ করা যেতে পারে । উদাহরণস্বরূপ, এটি বন্ধ করার আগে কোনও ফাইল খোলা আছে তা জোর দিয়ে, তারপরে ফাইল.ওপেন () একটি ওপেন ফাইলে টাইপ করতে পারে, যার মধ্যে একটি ক্লোজ () পদ্ধতি রয়েছে যা ফাইলটিতে নেই। একটি টিক-টাক-টো এপিআই হ'ল সংকলন সময়ে আক্রমণকারীদের প্রয়োগ করতে টাইপিং নিয়োগের আরেকটি উদাহরণ হতে পারে। টাইপ সিস্টেম এমনকি টুরিং-সম্পূর্ণ, যেমন হতে পারে Scala । নির্ভরশীলভাবে টাইপ করা ভাষা এবং উপপাদ্য প্রবাদগুলি উচ্চ-অর্ডার টাইপিংয়ের মডেলগুলিকে আনুষ্ঠানিক করে।

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

আমার তাত্ত্বিক অবস্থানটি হ'ল জ্ঞানের অস্তিত্ব থাকার জন্য (বিভাগ "কেন্দ্রিয়করণ অন্ধ এবং অযোগ্য" দেখুন), এমন কোনও সাধারণ মডেল কখনই পাওয়া যাবে না যা টুরিং-সম্পূর্ণ কম্পিউটার ভাষায় সমস্ত সম্ভাব্য আক্রমণকারীদের 100% কভারেজ প্রয়োগ করতে পারে। জ্ঞানের অস্তিত্ব থাকার জন্য, অপ্রত্যাশিত সম্ভাবনাগুলি অনেক বেশি বিদ্যমান, অর্থাৎ ব্যাধি এবং এনট্রপি অবশ্যই সর্বদা বৃদ্ধি পাবে। এটি হ'ল এন্ট্রোপিক শক্তি। সম্ভাব্য এক্সটেনশনের সমস্ত সম্ভাব্য গণনা প্রমাণ করার জন্য, সমস্ত সম্ভাব্য এক্সটেনশনের একটি অগ্রাধিকার গণনা করা।

এই কারণেই হ্যালটিং উপপাদ্য বিদ্যমান, অর্থাত্ এটি ট্যুরিং-সম্পূর্ণ প্রোগ্রামিং ভাষার প্রতিটি প্রোগ্রাম শেষ করে কিনা তা অনস্বীকার্য। এটি প্রমাণিত হতে পারে যে কিছু নির্দিষ্ট প্রোগ্রামের সমাপ্তি ঘটে (এমন একটি যা সমস্ত সম্ভাবনা সংজ্ঞায়িত এবং গণনা করা হয়)। তবে প্রমাণ করা অসম্ভব যে এই প্রোগ্রামটির সমস্ত সম্ভাব্য বর্ধন বন্ধ হয়ে যায়, যদি না সেই প্রোগ্রামের সম্প্রসারণের সম্ভাবনাগুলি টুরিং সম্পূর্ণ না হয় (যেমন নির্ভরশীল টাইপিংয়ের মাধ্যমে)। টুরিং-সম্পূর্ণতার জন্য মৌলিক প্রয়োজনীয়তা যেহেতু সীমাহীন পুনরাবৃত্তি , তাই গডেলের অসম্পূর্ণতা উপপাদাগুলি এবং রাসেলের প্যারাডক্সটি কীভাবে বর্ধনের ক্ষেত্রে প্রযোজ্য তা বোঝা স্বজ্ঞাত।

এই উপপাদ্যগুলির একটি ব্যাখ্যা এন্ট্রপিক শক্তির একটি সাধারণ ধারণাগত বোঝার সাথে তাদের অন্তর্ভুক্ত করে:

  • গডেলের অসম্পূর্ণতা উপপাদ্য : যে কোনও আনুষ্ঠানিক তত্ত্ব, যেখানে সমস্ত গাণিতিক সত্য প্রমাণিত হতে পারে, তা বেমানান।
  • রাসেলের প্যারাডক্স : একটি সেটের জন্য প্রতিটি সদস্যতার নিয়ম যা একটি সেট থাকতে পারে, তা হয় প্রতিটি সদস্যের নির্দিষ্ট ধরণের গণনা করে বা এতে থাকে। সুতরাং সেটগুলি হয় বাড়ানো যায় না বা সেগুলি সীমাহীন পুনরাবৃত্তি হয়। উদাহরণস্বরূপ, সমস্ত কিছুর একটি সেট যা একটি চাঁচা নয়, নিজেকে অন্তর্ভুক্ত করে, যার মধ্যে নিজেকে অন্তর্ভুক্ত থাকে, যার মধ্যে নিজেকে অন্তর্ভুক্ত করা হয়, ইত্যাদি…। সুতরাং একটি নিয়ম বেমানান হয় যদি এটিতে (একটি সেট থাকতে পারে এবং) নির্দিষ্ট ধরণের (যেমন সমস্ত অনির্দিষ্ট প্রকারকে অনুমতি দেয়) গণনা না করে এবং আনবাউন্ডেড এক্সটেনশনের অনুমতি না দেয়। এটি এমন সেটগুলির সেট যা নিজের সদস্য নয়। এই সমস্ত অক্ষমতা হ'ল গডেলের অসম্পূর্ণতা উপপাদ্যগুলি উভয়ই সামঞ্জস্যপূর্ণ এবং সমস্ত সম্ভাব্য বর্ধনের উপরে সম্পূর্ণরূপে গণনা করা।
  • লিসকভ সাবস্টিশন নীতি : সাধারণত কোনও সেট অন্যের উপসেট হ'ল অর্থাত্ উত্তরাধিকার সাধারণত অনস্বীকার্য কিনা তা অনস্বীকার্য সমস্যা।
  • লিনস্কি রেফারেন্সিং : কোনও কিছুর গণনা কী তা অনস্বীকার্য , যখন এটি বর্ণনা করা হয় বা অনুধাবন করা হয়, অর্থাৎ উপলব্ধির (বাস্তবতার) কোনও রেফারেন্সের পরম বিন্দু নেই।
  • কোয়েসের উপপাদ্য : কোনও বাহ্যিক রেফারেন্স পয়েন্ট নেই, সুতরাং সীমাহীন বাহ্যিক সম্ভাবনার কোনও বাধা ব্যর্থ হবে।
  • থার্মোডিনামিকসের দ্বিতীয় আইন : পুরো মহাবিশ্ব (একটি বদ্ধ সিস্টেম, অর্থাৎ সবকিছু) সর্বাধিক ব্যাধি, অর্থাৎ সর্বোচ্চ স্বাধীন সম্ভাবনার দিকে ঝোঁক।

17
@ শেলিবি: আপনি অনেকগুলি জিনিস মিশ্রিত করেছেন। বিষয়গুলি তেমনি বিভ্রান্তিকর নয় them আপনার বেশিরভাগ তাত্ত্বিক বক্তব্যগুলি ন্যূনতম ভিত্তিতে দাঁড়িয়ে আছে, যেমন 'জ্ঞানের অস্তিত্ব থাকতে পারে, অপ্রত্যাশিত সম্ভাবনা অনেক বেশি থাকে, .........' এবং 'সাধারণত কোনও সেট অন্যটির উপসেট কিনা তা অনস্বীকার্য সমস্যা ie উত্তরাধিকার সাধারণত অনস্বীকার্য '। আপনি এই পয়েন্টগুলির জন্য পৃথক ব্লগ শুরু করতে পারেন। যাইহোক, আপনার দাবি এবং অনুমানগুলি অত্যন্ত প্রশ্নবিদ্ধ। একজনকে এমন জিনিস ব্যবহার করা উচিত নয় যা সম্পর্কে সচেতন নয়!
আকোন

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

4
আপনি শেলবিমুর IIII আপনি অনেকগুলি দিকনির্দেশে যাচ্ছেন। এটি কোনও উত্তর নয়।
সোলডালমা

1
@ সোলডালমা এটি একটি উত্তর। আপনি উত্তর বিভাগে এটি দেখতে পাচ্ছেন না। আপনার মন্তব্য একটি মন্তব্য কারণ এটি মন্তব্য বিভাগে।
শেলবি মুর তৃতীয়

1
আপনার স্কেল ওয়ার্ল্ডের সাথে মিশ্রনের মতো!
এহসান এম। কেরমানি

23

আপনি লিসকভকে লঙ্ঘন করছেন কিনা তা নির্ধারণের জন্য একটি চেক তালিকা রয়েছে।

  • যদি আপনি নিম্নলিখিত আইটেমগুলির মধ্যে একটি লঙ্ঘন করেন -> আপনি লিসকভ লঙ্ঘন করেন।
  • আপনি যদি কোনও লঙ্ঘন না করেন -> কিছুই বলতে পারেন না।

চেক তালিকা:

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

    public class SuperType
    {
        public string Name { get; private set; }
        public SuperType(string name, int age)
        {
            Name = name;
            Age = age;
        }
    }
    public class SubType : SuperType
    {
        public void ChangeName(string newName)
        {
            var propertyType = base.GetType().GetProperty("Name").SetValue(this, newName);
        }
    }
    

আছে: 2 অন্যান্য আইটেম নেই পদ্ধতি আর্গুমেন্ট Contravariance এবং রিটার্ন ধরনের কোভ্যারিয়েন্স । তবে এটি সি # তে সম্ভব নয় (আমি একটি সি # বিকাশকারী) তাই আমি তাদের সম্পর্কে যত্ন নেব না।

রেফারেন্স:


আমি একজন সি # বিকাশকারীও এবং আমি আপনাদের শেষ বিবৃতিটি ভিজ্যুয়াল স্টুডিও ২০১০ হিসাবে ঠিক নেই, নেট নেট ফ্রেমওয়ার্কের সাথে জানাই। রিটার্ন প্রকারের সমাহার ইন্টারফেসের দ্বারা সংজ্ঞায়িত করা তার চেয়ে আরও বেশি উত্পন্ন রিটার্নের প্রকারের অনুমতি দেয়। উদাহরণ: উদাহরণ: আইনিউমেন্টেবল <টি> (টি হল সমকামী) আইকনোমিটার <টি> (টি হল সমকামী) আইগ্রুভিং <টি> (টি কোভেরিয়েন্ট) আইগ্রুপিং <টি কে, টিলেমেন্ট> (টি কে এবং টেলিমেন্ট কোভেরিয়েন্ট) আইসিএমপিয়ার <টি> (টি contravariant হয়) IEqualityComparer <টি> (টি contravariant হয়) IComparable <টি> (টি contravariant হয়) msdn.microsoft.com/en-us/library/dd233059(v=vs.100).aspx
LCarter

1
দুর্দান্ত এবং কেন্দ্রীভূত উত্তর (যদিও মূল প্রশ্নগুলি বিধিগুলির চেয়ে উদাহরণ সম্পর্কে বেশি ছিল)।
মাইক

23

আমি প্রতিটি উত্তরে আয়তক্ষেত্র এবং স্কোয়ারগুলি দেখতে পাচ্ছি এবং কীভাবে এলএসপিকে লঙ্ঘন করব।

আমি কীভাবে এলএসপিকে বাস্তব-বিশ্বের উদাহরণের সাথে রূপান্তর করতে পারি তা দেখাতে চাই:

<?php

interface Database 
{
    public function selectQuery(string $sql): array;
}

class SQLiteDatabase implements Database
{
    public function selectQuery(string $sql): array
    {
        // sqlite specific code

        return $result;
    }
}

class MySQLDatabase implements Database
{
    public function selectQuery(string $sql): array
    {
        // mysql specific code

        return $result; 
    }
}

এই নকশাটি এলএসপিকে সম্মতি জানায় কারণ ব্যবহারের জন্য আমরা যে প্রয়োগটি বেছে নিই তা আচরণটি অপরিবর্তিত রয়েছে।

এবং হ্যাঁ, আপনি এই কনফিগারেশনে এলএসপি লঙ্ঘন করতে পারেন এর মতো একটি সাধারণ পরিবর্তন করে:

<?php

interface Database 
{
    public function selectQuery(string $sql): array;
}

class SQLiteDatabase implements Database
{
    public function selectQuery(string $sql): array
    {
        // sqlite specific code

        return $result;
    }
}

class MySQLDatabase implements Database
{
    public function selectQuery(string $sql): array
    {
        // mysql specific code

        return ['result' => $result]; // This violates LSP !
    }
}

এখন সাবটাইপগুলি একইভাবে ব্যবহার করা যাবে না কারণ তারা আর একই ফল প্রকাশ করে না।


6
উদাহরণটি কেবলমাত্র LSP লঙ্ঘন করে না যতক্ষণ না আমরা সমস্ত ডিবি ইঞ্জিন Database::selectQueryদ্বারা সমর্থিত এসকিউএল-এর কেবলমাত্র উপসেটটি সমর্থন করার শব্দার্থকে সীমাবদ্ধ করি । এটি কঠোরভাবে ব্যবহারিক ... এটি বলেছে যে, উদাহরণটি এখানে ব্যবহার করা অন্যদের তুলনায় এখনও সহজ sp
প্যালেক

5
আমি এই উত্তরটি বাকী থেকে উপলব্ধি করা সবচেয়ে সহজ খুঁজে পেয়েছি।
ম্যালকম সালভাদোর

22

এলএসপি ক্লজগুলির চুক্তি সম্পর্কে একটি নিয়ম: যদি একটি বেস শ্রেণি একটি চুক্তি সন্তুষ্ট করে, তবে এলএসপি উত্পন্ন শ্রেণি দ্বারা অবশ্যই সেই চুক্তিটি সন্তুষ্ট করতে হবে।

সিউডো-পাইথনে

class Base:
   def Foo(self, arg): 
       # *... do stuff*

class Derived(Base):
   def Foo(self, arg):
       # *... do stuff*

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


9
তবে ... আপনি যদি সর্বদা একই আচরণ পান তবে ডাইরিভড ক্লাস করার কী লাভ?
লিওনিড

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

@ চার্লি মার্টিন, একটি প্রয়োগের পরিবর্তে একটি ইন্টারফেসে কোডিং - আমি এটি খনন করি। এটি ওওপির পক্ষে অনন্য নয়; ক্লোজারের মতো ক্রিয়ামূলক ভাষাও এটিকে প্রচার করে। এমনকি জাভা বা সি # এর ক্ষেত্রেও আমি মনে করি যে বিমূর্ত শ্রেণি প্লাস বর্গ শ্রেণিবদ্ধ ব্যবহারের চেয়ে ইন্টারফেস ব্যবহার করা আপনার দেওয়া উদাহরণগুলির পক্ষে স্বাভাবিক হবে। পাইথন দৃ strongly়ভাবে টাইপ করা হয় না এবং সত্যই ইন্টারফেস থাকে না, অন্তত স্পষ্টভাবে নয় not আমার অসুবিধা হ'ল আমি বেশ কয়েক বছর ধরে সলিডের সাথে মেনে না গিয়ে ওওপি করছি। এখন আমি এটি পেরিয়ে এসেছি বলে মনে হচ্ছে এটি সীমাবদ্ধ এবং প্রায় স্ব-বিরোধী।
হামিশ গ্রুবিজন

ঠিক আছে, আপনাকে ফিরে গিয়ে বার্বারার আসল কাগজটি পরীক্ষা করে দেখতে হবে। রিপোর্টসআরচ.ইডিএম.সি.সি.এম.ইউ / অ্যানন / ১৯৯৯ / সিএমইউ- সিএস -৯৯-১66.ps এটি ইন্টারফেসের ক্ষেত্রে প্রকৃতপক্ষে বর্ণিত হয়নি, এবং এটি একটি যৌক্তিক সম্পর্ক যা কোনওটিতেই (বা না) ধারণ করে প্রোগ্রামিং ভাষা যা উত্তরাধিকারের কিছু রূপ রয়েছে।
চার্লি মার্টিন

1
@ হামিশ গ্রুবিজান আমি জানি না কে আপনাকে বলেছিল যে পাইথন দৃ strongly়ভাবে টাইপ করা হয় না, তবে তারা আপনাকে মিথ্যাবাদী বলেছিল (এবং যদি আপনি আমাকে বিশ্বাস না করেন তবে একটি পাইথন দোভাষীকে আগুন দিয়ে চেষ্টা করুন 2 + "2")। সম্ভবত আপনি "স্ট্যাটিকালি টাইপড" দিয়ে "দৃ strongly় টাইপড" কে বিভ্রান্ত করছেন?
asmeurer

21

দীর্ঘ গল্প সংক্ষিপ্ত, আসুন আয়তক্ষেত্রগুলি এবং স্কোয়ার স্কোয়ারগুলি ছেড়ে দেওয়া যাক, পিতামাতার ক্লাস প্রসারিত করার সময় ব্যবহারিক উদাহরণ, আপনাকে হয় সঠিক প্যারেন্ট এপিআই প্রেরণ করতে হবে বা এটি প্রসারিত করতে হবে।

ধরা যাক আপনার একটি বেস আইটেমস রিপোসিটোরি রয়েছে।

class ItemsRepository
{
    /**
    * @return int Returns number of deleted rows
    */
    public function delete()
    {
        // perform a delete query
        $numberOfDeletedRows = 10;

        return $numberOfDeletedRows;
    }
}

এবং একটি উপশ্রেণী এটি প্রসারিত করছে:

class BadlyExtendedItemsRepository extends ItemsRepository
{
    /**
     * @return void Was suppose to return an INT like parent, but did not, breaks LSP
     */
    public function delete()
    {
        // perform a delete query
        $numberOfDeletedRows = 10;

        // we broke the behaviour of the parent class
        return;
    }
}

তারপরে আপনার ক্লায়েন্ট বেস আইটেমস রিপোসিটরি এপিআইয়ের সাথে কাজ করতে এবং তার উপর নির্ভর করতে পারেন।

/**
 * Class ItemsService is a client for public ItemsRepository "API" (the public delete method).
 *
 * Technically, I am able to pass into a constructor a sub-class of the ItemsRepository
 * but if the sub-class won't abide the base class API, the client will get broken.
 */
class ItemsService
{
    /**
     * @var ItemsRepository
     */
    private $itemsRepository;

    /**
     * @param ItemsRepository $itemsRepository
     */
    public function __construct(ItemsRepository $itemsRepository)
    {
        $this->itemsRepository = $itemsRepository;
    }

    /**
     * !!! Notice how this is suppose to return an int. My clients expect it based on the
     * ItemsRepository API in the constructor !!!
     *
     * @return int
     */
    public function delete()
    {
        return $this->itemsRepository->delete();
    }
} 

LSP যখন নষ্ট হয়ে গেছে বদলে পিতা বা মাতা একটি সঙ্গে বর্গ সাব বর্গ বিরতি এপিআই চুক্তির

class ItemsController
{
    /**
     * Valid delete action when using the base class.
     */
    public function validDeleteAction()
    {
        $itemsService = new ItemsService(new ItemsRepository());
        $numberOfDeletedItems = $itemsService->delete();

        // $numberOfDeletedItems is an INT :)
    }

    /**
     * Invalid delete action when using a subclass.
     */
    public function brokenDeleteAction()
    {
        $itemsService = new ItemsService(new BadlyExtendedItemsRepository());
        $numberOfDeletedItems = $itemsService->delete();

        // $numberOfDeletedItems is a NULL :(
    }
}

আপনি আমার কোর্সে রক্ষণাবেক্ষণযোগ্য সফ্টওয়্যার লেখার বিষয়ে আরও শিখতে পারেন: https://www.udemy.com/enterprise-php/


20

বেস ক্লাসে পয়েন্টার বা রেফারেন্স ব্যবহার করে এমন ফাংশনগুলি অজান্তেই উত্পন্ন ক্লাসের অবজেক্টগুলি ব্যবহার করতে সক্ষম হতে হবে।

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

ধারণাটি আরও পড়ার পরে যদিও আমি দেখতে পেলাম যে এলএসপি সাধারণত তার চেয়ে বেশি বিস্তৃতভাবে ব্যাখ্যা করা হয়।

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

আবার উদাহরণের দিকে ফিরে যাওয়া, তত্ত্বে বোর্ড পদ্ধতিগুলিকে থ্রিডিবোর্ডে ঠিকঠাক কাজ করার জন্য তৈরি করা যেতে পারে। তবে অনুশীলনে, থ্রিডিবোর্ড যুক্ত করার উদ্দেশ্যে যে কার্যকারিতাটি ক্লিচটি সঠিকভাবে পরিচালনা করতে পারে না তার আচরণের পার্থক্য প্রতিরোধ করা খুব কঠিন হবে client

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


19

প্রযুক্তিবিদগতভাবে এলএসপিতে যা রয়েছে তা প্রত্যেকেরই আমি কভার করেছি বলে অনুমান করি: আপনি মূলত সাব টাইপের বিবরণ থেকে দূরে থাকতে এবং নিরাপদে সুপারটাইপগুলি নিরাপদে ব্যবহার করতে সক্ষম হতে চান।

সুতরাং লিসকভের 3 টি অন্তর্নিহিত নিয়ম রয়েছে:

  1. স্বাক্ষর বিধি: সাব টাইপের সিনট্যাক্টিক্যালি সুপার টাইপের প্রতিটি ক্রিয়াকলাপের বৈধ প্রয়োগ হওয়া উচিত। কিছু সংকলক আপনার জন্য যাচাই করতে সক্ষম হবে। কম ব্যতিক্রম ছোঁড়া এবং সুপারটাইপ পদ্ধতিগুলির মতো কমপক্ষে অ্যাক্সেসযোগ্য হওয়া সম্পর্কে একটি সামান্য নিয়ম আছে।

  2. পদ্ধতির বিধি: এই ক্রিয়াকলাপগুলির বাস্তবায়ন শব্দার্থগতভাবে দৃ is়।

    • দুর্বল পূর্বশর্ত: সাবটাইপ ফাংশনগুলির কমপক্ষে কমপক্ষে ইনপুট হিসাবে কী গ্রহণ করেছে তা গ্রহণ করা উচিত।
    • শক্তিশালী পোস্টকন্ডিশনস: তাদের সুপারপাইপগুলি উত্পাদিত আউটপুটটির একটি উপসেট তৈরি করা উচিত।
  3. প্রোপার্টি বিধি: এটি পৃথক ফাংশন কলের বাইরে goes

    • আক্রমণকারী: যে জিনিসগুলি সর্বদা সত্য তা অবশ্যই সত্য থাকতে হবে। যেমন। একটি সেটের আকার কখনই নেতিবাচক হয় না।
    • বিবর্তনমূলক বৈশিষ্ট্য: সাধারণত অপরিবর্তনশীলতা বা অবজেক্টের ধরণের অবস্থার সাথে কিছু করার জন্য Or

এই সমস্ত বৈশিষ্ট্য সংরক্ষণ করা দরকার এবং অতিরিক্ত সাব টাইপ কার্যকারিতা সুপারটাইপ বৈশিষ্ট্য লঙ্ঘন করা উচিত নয়।

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

সূত্র: জাভাতে প্রোগ্রাম ডেভলপমেন্ট - বারবারা লিসকভ


18

এলএসপি ব্যবহারের একটি গুরুত্বপূর্ণ উদাহরণটি সফ্টওয়্যার পরীক্ষায়

যদি আমার A এর একটি ক্লাস থাকে যা B এর LSP- অনুবর্তী সাবক্লাস হয়, তবে আমি B এর পরীক্ষার স্যুটটি A এর সাথে পুনরায় ব্যবহার করতে পারি A.

সাবক্লাস এ পুরোপুরি পরীক্ষা করার জন্য, আমার সম্ভবত আরও কয়েকটি পরীক্ষার কেস যুক্ত করা দরকার, তবে সর্বনিম্ন আমি সুপারক্লাস বি এর সমস্ত পরীক্ষার ক্ষেত্রে পুনরায় ব্যবহার করতে পারি।

ম্যাকগ্রিগর যাকে "পরীক্ষার জন্য সমান্তরাল শ্রেণিবিন্যাস" বলে ডাকে তা বোঝার একটি উপায়: আমার ATestক্লাসটি উত্তরাধিকার সূত্রে প্রাপ্ত হবে BTest। ইনজেকশনের কিছু ফর্মের পরে পরীক্ষার কেস বি টাইপের পরিবর্তে টাইপ এ এর ​​বস্তুর সাথে কাজ করে তা নিশ্চিত করার জন্য প্রয়োজনীয় (একটি সাধারণ টেম্পলেট পদ্ধতি প্যাটার্নটি করবে)।

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

স্ট্যাকওভারফ্লো প্রশ্নের উত্তরটিও দেখুন " আমি কোনও ইন্টারফেসের বাস্তবায়ন পরীক্ষা করতে পুনরায় পুনরায় ব্যবহারযোগ্য পরীক্ষাগুলি প্রয়োগ করতে পারি? "


13

আসুন জাভাতে চিত্রিত করুন:

class TrasportationDevice
{
   String name;
   String getName() { ... }
   void setName(String n) { ... }

   double speed;
   double getSpeed() { ... }
   void setSpeed(double d) { ... }

   Engine engine;
   Engine getEngine() { ... }
   void setEngine(Engine e) { ... }

   void startEngine() { ... }
}

class Car extends TransportationDevice
{
   @Override
   void startEngine() { ... }
}

এখানে কোন সমস্যা নেই, তাই না? একটি গাড়ী অবশ্যই একটি পরিবহণ ডিভাইস এবং এখানে আমরা দেখতে পাচ্ছি যে এটি তার সুপারক্লাসের স্টার্টইঞ্জিন () পদ্ধতিটিকে ওভাররাইড করে।

আসুন অন্য পরিবহন ডিভাইস যুক্ত করুন:

class Bicycle extends TransportationDevice
{
   @Override
   void startEngine() /*problem!*/
}

সবকিছু এখন পরিকল্পনা মতো চলছে না! হ্যাঁ, একটি সাইকেলটি একটি পরিবহন ডিভাইস, তবে এর কোনও ইঞ্জিন নেই এবং তাই, স্টার্টইঙ্গিন () পদ্ধতিটি প্রয়োগ করা যায় না।

লিসকভ সাবস্টিটিউশন নীতি লঙ্ঘনের ফলে এ ধরণের সমস্যা দেখা দেয় এবং এগুলি সাধারণত এমন কোনও পদ্ধতি দ্বারা স্বীকৃত হতে পারে যা কিছুই করে না, এমনকি বাস্তবায়নও করা যায় না।

এই সমস্যার সমাধান হ'ল উত্তরাধিকারের শ্রেণিবিন্যাস, এবং আমাদের ক্ষেত্রে আমরা ইঞ্জিনের সাথে এবং তার ছাড়াই পরিবহন ডিভাইসের ক্লাসকে আলাদা করে সমস্যার সমাধান করব। সাইকেলটি একটি পরিবহন যন্ত্র হলেও এটিতে ইঞ্জিন নেই। এই উদাহরণে পরিবহন ডিভাইসের আমাদের সংজ্ঞাটি ভুল। এটিতে ইঞ্জিন থাকা উচিত নয়।

আমরা আমাদের ট্রান্সপোর্টেশন ডিভাইস ক্লাসটি নিম্নরূপ রিফ্যাক্টর করতে পারি:

class TrasportationDevice
{
   String name;
   String getName() { ... }
   void setName(String n) { ... }

   double speed;
   double getSpeed() { ... }
   void setSpeed(double d) { ... }
}

এখন আমরা নন-মোটরযুক্ত ডিভাইসগুলির জন্য পরিবহন যন্ত্রটি প্রসারিত করতে পারি।

class DevicesWithoutEngines extends TransportationDevice
{  
   void startMoving() { ... }
}

এবং মোটরযুক্ত ডিভাইসগুলির জন্য পরিবহন ডিভাইস প্রসারিত করুন। ইঞ্জিন অবজেক্ট যুক্ত করার জন্য এখানে আরও উপযুক্ত।

class DevicesWithEngines extends TransportationDevice
{  
   Engine engine;
   Engine getEngine() { ... }
   void setEngine(Engine e) { ... }

   void startEngine() { ... }
}

এইভাবে লিসকভ সাবস্টিটিউশন নীতি মেনে চলাকালীন আমাদের গাড়ি শ্রেণি আরও বিশেষায়িত হয়ে ওঠে।

class Car extends DevicesWithEngines
{
   @Override
   void startEngine() { ... }
}

এবং আমাদের সাইকেল শ্রেণিটি লিসকভ সাবস্টিটিউশন নীতিমালার সাথেও মেনে চলে।

class Bicycle extends DevicesWithoutEngines
{
   @Override
   void startMoving() { ... }
}

9

এলএসপির এই সূত্রটি বেশ শক্তিশালী:

টাইপ এস এর প্রতিটি বস্তুর ও 1 এর জন্য টি টাইপ টির একটি অবজেক্ট ও 2 থাকে যে সমস্ত প্রোগ্রামের জন্য টি এর শর্তাবলী পি ডি-এনড হয়, যখন ও 1 টি ও 2 এর পরিবর্তে পি এর আচরণটি অপরিবর্তিত থাকে তবে এস টি টির একটি উপ-টাইপ হয় is

যার মূলত এসটি হ'ল অন্যটি, টি হিসাবে ঠিক একই জিনিসটির সম্পূর্ণ প্রয়োগকে বাস্তবায়িত করে And

সুতরাং, মূলত, দেরি-বাঁধাইয়ের যে কোনও ব্যবহার এলএসপিকে লঙ্ঘন করে। যখন আমরা এক প্রকারের কোনও জিনিসের জন্য অন্য ধরণের একেকটির বিকল্প রাখি তখন ভিন্ন আচরণ অর্জন করা ওওর পুরো বিষয়!

উইকিপিডিয়া দ্বারা উদ্ধৃত সূত্রটি আরও ভাল কারণ সম্পত্তি প্রসঙ্গে নির্ভর করে এবং প্রোগ্রামের পুরো আচরণটি অগত্যা অন্তর্ভুক্ত করে না।


2
এরম, সেই সূত্রটি বারবারা লিসকভের নিজস্ব। বারবারা লিসকভ, "ডেটা অ্যাবস্ট্রাকশন অ্যান্ড হায়ারার্কি," সিগপ্ল্যান নোটিশ, 23,5 (মে, 1988)। এটি "উপায় খুব শক্তিশালী" নয়, এটি "হুবহু সঠিক", এবং এটি আপনার মনে করে যে এটি জড়িত বলে মনে হয় না। এটি শক্তিশালী, তবে শক্তি মাত্র সঠিক পরিমাণে।
ড্রিপিজা

তারপরে, বাস্তব জীবনে খুব কম সাব টাইপ রয়েছে :)
ড্যামিয়েন পোলেট

3
"আচরণটি অপরিবর্তিত" এর অর্থ এই নয় যে একটি উপপ্রকার আপনাকে সঠিক একই কংক্রিট ফলাফলের মান (গুলি) দেবে। এর অর্থ হ'ল সাব টাইপের আচরণটি বেস প্রকারের প্রত্যাশার সাথে মেলে। উদাহরণ: বেস টাইপ শেপের একটি অঙ্কন () পদ্ধতি থাকতে পারে এবং এই পদ্ধতিটি আকারটি রেন্ডার করে p শেপের দুটি সাব টাইপ (যেমন স্কোয়ার এবং সার্কেল) উভয়ই অঙ্কন () পদ্ধতি বাস্তবায়িত করবে এবং ফলাফলগুলি পৃথক দেখবে। তবে যতক্ষণ আচরণ (আকৃতিটি প্রেরণ করা) শেপের নির্দিষ্ট আচরণের সাথে মেলে ততক্ষণ স্কয়ার এবং সার্কেলটি এলএসপি অনুসারে শেপের সাব-টাইপ হবে pes
স্টিভটি

9

খুব সাধারণ বাক্যে আমরা বলতে পারি:

শিশু শ্রেণী অবশ্যই এর বেস শ্রেণির বৈশিষ্ট্যগুলি লঙ্ঘন করবে না। এটি অবশ্যই এটির সাথে সক্ষম হতে হবে। আমরা এটি সাব টাইপিংয়ের মতোই বলতে পারি।


9

লিসকভের সাবস্টিটিউশন নীতি (এলএসপি)

সারাক্ষণ আমরা একটি প্রোগ্রাম মডিউল ডিজাইন করি এবং আমরা কিছু শ্রেণি শ্রেণিবিন্যাস তৈরি করি। তারপরে আমরা কিছু উত্পন্ন ক্লাস তৈরি করে কিছু শ্রেণি প্রসারিত করি।

আমাদের অবশ্যই নিশ্চিত করতে হবে যে নতুন উত্পন্ন ক্লাসগুলি কেবল পুরানো শ্রেণীর কার্যকারিতা প্রতিস্থাপন না করে প্রসারিত হবে। অন্যথায়, নতুন ক্লাসগুলি বিদ্যমান প্রোগ্রাম মডিউলগুলিতে ব্যবহৃত হলে অনাকাঙ্ক্ষিত প্রভাব তৈরি করতে পারে।

লিসকভের সাবস্টিটিউশন নীতিতে বলা হয়েছে যে কোনও প্রোগ্রাম মডিউল যদি বেস ক্লাস ব্যবহার করে তবে প্রোগ্রাম মডিউলের কার্যকারিতা প্রভাবিত না করে বেস ক্লাসের রেফারেন্সটি ডেরাইভড ক্লাসের সাথে প্রতিস্থাপন করা যেতে পারে।

উদাহরণ:

নীচে ক্লাসিক উদাহরণ দেওয়া আছে যার জন্য লিসকোভের সাবস্টিটিউশন নীতি লঙ্ঘন করা হয়েছে। উদাহরণস্বরূপ, 2 টি ক্লাস ব্যবহৃত হয়: আয়তক্ষেত্র এবং স্কোয়ার। আসুন ধরে নেওয়া যাক রেক্টেঙ্গেল অবজেক্টটি অ্যাপ্লিকেশনটির কোথাও ব্যবহৃত হয়েছে। আমরা অ্যাপ্লিকেশনটি প্রসারিত করি এবং স্কোয়ার শ্রেণি যুক্ত করি। কিছু শর্তের উপর ভিত্তি করে বর্গাকার শ্রেণিটি কারখানার প্যাটার্ন দ্বারা ফিরে আসে এবং কোন ধরণের অবজেক্টটি ফিরে আসবে তা সঠিকভাবে আমরা জানি না। তবে আমরা জানি এটি একটি আয়তক্ষেত্র। আমরা আয়তক্ষেত্রের অবজেক্টটি পাই, প্রস্থটি 5 এবং উচ্চতায় 10 এ সেট করব এবং অঞ্চলটি পাই। প্রস্থ 5 এবং উচ্চতা 10 সহ একটি আয়তক্ষেত্রের জন্য ক্ষেত্রফল 50 হওয়া উচিত Instead পরিবর্তে, ফলাফলটি 100 হবে

    // Violation of Likov's Substitution Principle
class Rectangle {
    protected int m_width;
    protected int m_height;

    public void setWidth(int width) {
        m_width = width;
    }

    public void setHeight(int height) {
        m_height = height;
    }

    public int getWidth() {
        return m_width;
    }

    public int getHeight() {
        return m_height;
    }

    public int getArea() {
        return m_width * m_height;
    }
}

class Square extends Rectangle {
    public void setWidth(int width) {
        m_width = width;
        m_height = width;
    }

    public void setHeight(int height) {
        m_width = height;
        m_height = height;
    }

}

class LspTest {
    private static Rectangle getNewRectangle() {
        // it can be an object returned by some factory ...
        return new Square();
    }

    public static void main(String args[]) {
        Rectangle r = LspTest.getNewRectangle();

        r.setWidth(5);
        r.setHeight(10);
        // user knows that r it's a rectangle.
        // It assumes that he's able to set the width and height as for the base
        // class

        System.out.println(r.getArea());
        // now he's surprised to see that the area is 100 instead of 50.
    }
}

উপসংহার:

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

আরও দেখুন: ওপেন ক্লোজ নীতি

আরও ভাল কাঠামোর জন্য অনুরূপ কিছু ধারণা: কনফিগারেশন ওপরে কনভেনশন


8

লিসকভ সাবস্টিটিউশন নীতি

  • ওভাররাইড হওয়া পদ্ধতিটি খালি রাখা উচিত নয়
  • ওভাররাইড হওয়া পদ্ধতিতে ত্রুটি ছোঁড়া উচিত নয়
  • বেস ক্লাস বা ইন্টারফেস আচরণটি পরিবর্তিত শ্রেণীর আচরণের কারণে পরিবর্তনের (পুনরায় কাজ) করা উচিত নয়।

7

কিছু সংযোজন:
আমি অবাক হই যে কেন বেসর শ্রেণীর ইনভেরেন্ট, পূর্বশর্ত এবং পোস্ট শর্তাদি সম্পর্কে কেউ কেন লিখেনি? বেস বর্গ বি দ্বারা সম্পূর্ণভাবে টেকসইযোগ্য হওয়ার জন্য ডিগ্রিযুক্ত ক্লাস ডি এর জন্য, ক্লাস ডি অবশ্যই কিছু শর্ত মেনে চলতে হবে:

  • বেস শ্রেণীর ইন-ভেরিয়েন্টগুলি অবশ্যই উত্পন্ন শ্রেণীর দ্বারা সংরক্ষণ করা উচিত
  • বেস শ্রেণীর প্রাক-শর্তাদি অবশ্যই উত্পন্ন শ্রেণীর দ্বারা শক্তিশালী করা উচিত নয়
  • বেস শ্রেণীর পোস্ট-শর্তাদি উত্পন্ন শ্রেণীর দ্বারা দুর্বল করা উচিত নয়।

সুতরাং প্রাপ্ত উত্সকে অবশ্যই বেস শ্রেণীর দ্বারা আরোপিত উপরের তিনটি শর্ত সম্পর্কে সচেতন হতে হবে। অতএব, সাব টাইপিংয়ের নিয়মগুলি পূর্ব নির্ধারিত। যার অর্থ, 'আইএস এ' সম্পর্ক কেবল তখনই মেনে নেওয়া হবে যখন নির্দিষ্ট নিয়মগুলি সাব টাইপ অনুসারে মেনে চলবে। এই নিয়মগুলি, আক্রমণকারী, পূর্বের শর্ত এবং পোস্টকন্ডিশনের আকারে একটি আনুষ্ঠানিক ' ডিজাইন চুক্তি ' দ্বারা সিদ্ধান্ত নেওয়া উচিত ।

আমার ব্লগে এই সম্পর্কিত আরও আলোচনা: লিসকভ সাবস্টিটিউশন নীতি


6

সহজ পদ LSP রাজ্যের যে একই সুপারক্লাস অবজেক্ট সক্ষম হওয়া উচিত হবে অদলবদল কিছু ভঙ্গ ছাড়া একে অপরের সাথে।

উদাহরণস্বরূপ, যদি আমাদের কাছে ক্লাস থেকে উদ্ভূত একটি Catএবং একটি Dogক্লাস থাকে Animalতবে প্রাণী শ্রেণীর ব্যবহার করে যে কোনও ফাংশন ব্যবহার করতে Catবা Dogস্বাভাবিকভাবে আচরণ করতে সক্ষম হতে হবে be


4

বোর্ডের অ্যারের শর্তে থ্রিডিবোর্ড কার্যকর করা কি কার্যকর হবে?

সম্ভবত আপনি বোর্ড হিসাবে বিভিন্ন প্লেনে থ্রিডিবোর্ডের স্লাইসগুলি আচরণ করতে চাইতে পারেন। সেক্ষেত্রে আপনি বোর্ডের একাধিক বাস্তবায়নের অনুমতি দেওয়ার জন্য একটি ইন্টারফেস (বা বিমূর্ত শ্রেণি) বিমূর্ত করতে চাইতে পারেন।

বাহ্যিক ইন্টারফেসের ক্ষেত্রে, আপনি টুডিবোর্ড এবং থ্রিডিবোর্ড উভয়ের জন্য বোর্ড ইন্টারফেস তৈরি করতে চাইতে পারেন (যদিও উপরের পদ্ধতির কোনওটিই মাপসই নয়)।


1
আমি মনে করি উদাহরণটি কেবল এটি প্রমাণ করার জন্য যে বোর্ড থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হওয়া থ্রিডিবোর্ডের প্রসঙ্গে বোঝা যায় না এবং সমস্ত পদ্ধতি স্বাক্ষর একটি জেড অক্ষের সাথে অর্থহীন।
নিজেই

4

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

অতএব একটি আকার পরিবর্তনযোগ্য বর্গক্ষেত্র কোন আকার পরিবর্তনযোগ্য আয়তক্ষেত্র নয়।


4

এই নীতিটি বারবারা লিসকভ 1987 সালে প্রবর্তন করেছিলেন এবং একটি সুপারক্লাসের আচরণ এবং এর উপ-প্রকারের প্রতি মনোনিবেশ করে ওপেন-ক্লোজড নীতিটি প্রসারিত করে।

যখন আমরা এটি লঙ্ঘনের পরিণতি বিবেচনা করি তখন এর গুরুত্বটি সুস্পষ্ট হয়ে যায়। নিম্নলিখিত শ্রেণীর ব্যবহার করে এমন একটি অ্যাপ্লিকেশন বিবেচনা করুন।

public class Rectangle 
{ 
  private double width;

  private double height; 

  public double Width 
  { 
    get 
    { 
      return width; 
    } 
    set 
    { 
      width = value; 
    }
  } 

  public double Height 
  { 
    get 
    { 
      return height; 
    } 
    set 
    { 
      height = value; 
    } 
  } 
}

কল্পনা করুন যে একদিন, ক্লায়েন্ট আয়তক্ষেত্রগুলি ছাড়াও স্কোয়ারগুলি পরিচালনা করার দক্ষতা দাবি করে। যেহেতু একটি বর্গক্ষেত্র একটি আয়তক্ষেত্র, বর্গক্ষেত্রটি আয়তক্ষেত্র শ্রেণীর থেকে নেওয়া উচিত।

public class Square : Rectangle
{
} 

তবে, এটি করে আমরা দুটি সমস্যার মুখোমুখি হব:

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

public class Square : Rectangle
{
  public double SetWidth 
  { 
    set 
    { 
      base.Width = value; 
      base.Height = value; 
    } 
  } 

  public double SetHeight 
  { 
    set 
    { 
      base.Height = value; 
      base.Width = value; 
    } 
  } 
}

এখন, যখন কেউ একটি বর্গক্ষেত্রের প্রস্থ নির্ধারণ করবে, তার উচ্চতা অনুসারে পরিবর্তিত হবে এবং তদ্বিপরীত হবে।

Square s = new Square(); 
s.SetWidth(1); // Sets width and height to 1. 
s.SetHeight(2); // sets width and height to 2. 

আসুন এগিয়ে যান এবং এই অন্যান্য ফাংশন বিবেচনা করুন:

public void A(Rectangle r) 
{ 
  r.SetWidth(32); // calls Rectangle.SetWidth 
} 

যদি আমরা এই ফাংশনে কোনও বর্গক্ষেত্রের কোনও রেফারেন্স পাস করি তবে আমরা LSP লঙ্ঘন করব কারণ ফাংশনটি তার আর্গুমেন্টগুলির ডেরিভেটিভসের জন্য কাজ করে না। বৈশিষ্ট্যগুলির প্রস্থ এবং উচ্চতা বহুতল নয় কারণ এগুলি আয়তক্ষেত্রগুলিতে ভার্চুয়াল হিসাবে ঘোষিত হয়নি (বর্গক্ষেত্রটি দূষিত হবে কারণ উচ্চতা পরিবর্তন হবে না)।

তবে সেটার বৈশিষ্ট্যগুলিকে ভার্চুয়াল হিসাবে ঘোষণা করে আমরা আরেকটি লঙ্ঘনের মুখোমুখি হব, ওসিপি। প্রকৃতপক্ষে, একটি উত্পন্ন শ্রেণিবদ্ধ বর্গক্ষেত্র তৈরি বেস শ্রেণীর আয়তক্ষেত্রের পরিবর্তন ঘটায়।


3

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


1
স্ট্যাকওভারফ্লোতে কোডের উদাহরণ সরবরাহ করুন।
sebenalern

3

ধরা যাক আমরা আমাদের কোডে একটি আয়তক্ষেত্র ব্যবহার করি

r = new Rectangle();
// ...
r.setDimensions(1,2);
r.fill(colors.red());
canvas.draw(r);

আমাদের জ্যামিতি ক্লাসে আমরা শিখেছি যে একটি বর্গক্ষেত্র একটি বিশেষ ধরণের আয়তক্ষেত্র কারণ এর প্রস্থ এটির দৈর্ঘ্যের সমান দৈর্ঘ্য। Squareএই তথ্যের উপর ভিত্তি করে একটি ক্লাস করা যাক :

class Square extends Rectangle {
    setDimensions(width, height){
        assert(width == height);
        super.setDimensions(width, height);
    }
} 

আমরা যদি আমাদের প্রথম কোডটির Rectangleসাথে প্রতিস্থাপন করি Square, তবে এটি ভেঙে যাবে:

r = new Square();
// ...
r.setDimensions(1,2); // assertion width == height failed
r.fill(colors.red());
canvas.draw(r);

এর কারণ Squareএকটি নতুন পূর্বশর্ত আমরা না হয়েছে Rectangleশ্রেণী: width == height। এলএসপি অনুসারে Rectangleউদাহরণগুলি Rectangleসাবক্লাস উদাহরণগুলির সাথে পরিবর্তিত হওয়া উচিত । কারণ এই দৃষ্টান্তগুলি উদাহরণগুলির জন্য টাইপ চেকটি পাস করে Rectangleএবং তাই এটি আপনার কোডে অপ্রত্যাশিত ত্রুটি ঘটায়।

এই জন্য একটি উদাহরণ ছিল "পূর্বশর্ত একটি উপপ্রকার জোরদার যাবে না" অংশগ্রহণ উইকি নিবন্ধে । সুতরাং সংক্ষেপে, LSP লঙ্ঘন সম্ভবত কোনও সময়ে আপনার কোডে ত্রুটি ঘটবে।


3

এলএসপি বলে যে '' অবজেক্টগুলি তাদের সাব টাইপগুলি দ্বারা প্রতিস্থাপনযোগ্য হওয়া উচিত ''। অন্যদিকে, এই নীতিটি নির্দেশ করে

চাইল্ড ক্লাসগুলি কখনই পিতামাতার শ্রেণীর ধরণের সংজ্ঞা ভঙ্গ করা উচিত নয়।

এবং নিম্নলিখিত উদাহরণটি এলএসপির আরও ভাল ধারণা পেতে সহায়তা করে।

এলএসপি ছাড়াই:

public interface CustomerLayout{

    public void render();
}


public FreeCustomer implements CustomerLayout {
     ...
    @Override
    public void render(){
        //code
    }
}


public PremiumCustomer implements CustomerLayout{
    ...
    @Override
    public void render(){
        if(!hasSeenAd)
            return; //it isn`t rendered in this case
        //code
    }
}

public void renderView(CustomerLayout layout){
    layout.render();
}

এলএসপি দ্বারা স্থিরকরণ:

public interface CustomerLayout{
    public void render();
}


public FreeCustomer implements CustomerLayout {
     ...
    @Override
    public void render(){
        //code
    }
}


public PremiumCustomer implements CustomerLayout{
    ...
    @Override
    public void render(){
        if(!hasSeenAd)
            showAd();//it has a specific behavior based on its requirement
        //code
    }
}

public void renderView(CustomerLayout layout){
    layout.render();
}

2

আমি আপনাকে নিবন্ধটি পড়তে উত্সাহিত করছি: লসকোভ সাবস্টিটিউশন নীতিমালা (এলএসপি) লঙ্ঘন করা

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


2

লিসকভ সাবস্টিটিউশন প্রিন্সিপল (মার্ক সিমেন বই থেকে) বলেছে যে আমাদের কোনও ইন্টারফেসের একটি প্রয়োগকে অন্য কোনও ক্লায়েন্ট বা বাস্তবায়ন না ভেঙে প্রতিস্থাপন করতে সক্ষম হওয়া উচিত। এটি এই নীতিটি যা ভবিষ্যতে ঘটে যাওয়া প্রয়োজনীয়তাগুলি সমাধান করতে সক্ষম করে, এমনকি আমরা যদি পারি ' আজ তাদের পূর্বেই আশা করি।

আমরা যদি কম্পিউটারটি প্রাচীর (প্রয়োগ) থেকে আনপ্লাগ করি, তবে প্রাচীরের আউটলেট (ইন্টারফেস) বা কম্পিউটার (ক্লায়েন্ট) বিচ্ছিন্ন হয় না (আসলে এটি যদি ল্যাপটপের কম্পিউটার হয় তবে এটি তার ব্যাটারিতেও কিছু সময়ের জন্য চালাতে পারে) । সফ্টওয়্যার সহ, তবে ক্লায়েন্ট প্রায়শই কোনও পরিষেবা উপলব্ধ হওয়ার প্রত্যাশা করে। যদি পরিষেবাটি সরিয়ে ফেলা হয় তবে আমরা একটি নালরফেরান এক্সেক্সেশন পাই। এই ধরণের পরিস্থিতি মোকাবেলা করার জন্য, আমরা একটি ইন্টারফেসের একটি বাস্তবায়ন তৈরি করতে পারি যা "কিছুই না" করে। এটি নুল অবজেক্ট নামে পরিচিত একটি নকশার প্যাটার্ন, [৪] এবং এটি দেওয়াল থেকে কম্পিউটারকে আনপ্লাগ করার সাথে মোটামুটি মিলিয়ে যায়। যেহেতু আমরা আলগা দম্পতি ব্যবহার করছি, আমরা এমন বাস্তবের সাথে বাস্তব বাস্তবায়ন প্রতিস্থাপন করতে পারি যা সমস্যার কারণ না করে কিছুই করে না।


2

লিকভের সাবস্টিটিউশন নীতিতে বলা হয়েছে যে কোনও প্রোগ্রাম মডিউল যদি বেস ক্লাস ব্যবহার করে তবে প্রোগ্রাম মডিউলের কার্যকারিতা প্রভাবিত না করে বেস ক্লাসের রেফারেন্সটি ডেরাইভড শ্রেণীর সাথে প্রতিস্থাপন করা যেতে পারে।

অভিপ্রায় - উত্পন্ন প্রকারগুলি অবশ্যই তাদের বেস ধরণের জন্য সম্পূর্ণ বিকল্প সক্ষম হতে হবে।

উদাহরণ - জাভাতে সহ-বৈকল্পিক রিটার্নের প্রকারগুলি।


1

এই পোস্টের একটি অংশ এখানে সুন্দরভাবে বিষয়গুলি পরিষ্কার করে:

[..] কিছু নীতি বোঝার জন্য, কখন এটি লঙ্ঘন করা হয়েছে তা উপলব্ধি করা গুরুত্বপূর্ণ important এই আমি এখন কি করব।

এই নীতি লঙ্ঘন মানে কি? এটি বোঝায় যে কোনও বস্তু কোনও ইন্টারফেসের মাধ্যমে প্রকাশিত বিমূর্ততার দ্বারা আরোপিত চুক্তিটি পূরণ করে না। অন্য কথায়, এর অর্থ হ'ল আপনি নিজের বিমূর্ততা ভুল চিহ্নিত করেছেন।

নিম্নলিখিত উদাহরণ বিবেচনা করুন:

interface Account
{
    /**
     * Withdraw $money amount from this account.
     *
     * @param Money $money
     * @return mixed
     */
    public function withdraw(Money $money);
}
class DefaultAccount implements Account
{
    private $balance;
    public function withdraw(Money $money)
    {
        if (!$this->enoughMoney($money)) {
            return;
        }
        $this->balance->subtract($money);
    }
}

এটি কি এলএসপির লঙ্ঘন? হ্যাঁ. এটি কারণ অ্যাকাউন্টের চুক্তিটি আমাদের বলে যে কোনও অ্যাকাউন্ট প্রত্যাহার করা হবে, তবে এটি সর্বদা ক্ষেত্রে হয় না। সুতরাং, এটি ঠিক করার জন্য আমার কী করা উচিত? আমি কেবল চুক্তিটি সংশোধন করেছি:

interface Account
{
    /**
     * Withdraw $money amount from this account if its balance is enough.
     * Otherwise do nothing.
     *
     * @param Money $money
     * @return mixed
     */
    public function withdraw(Money $money);
}

ভাল, এখন চুক্তি সন্তুষ্ট।

এই সূক্ষ্ম লঙ্ঘন প্রায়শই নিযুক্ত কংক্রিটের মধ্যে পার্থক্য বলার ক্ষমতা সহ একটি ক্লায়েন্টকে চাপিয়ে দেয়। উদাহরণস্বরূপ, প্রথম অ্যাকাউন্টের চুক্তি দেওয়া, এটি নিম্নলিখিতগুলির মতো দেখাতে পারে:

class Client
{
    public function go(Account $account, Money $money)
    {
        if ($account instanceof DefaultAccount && !$account->hasEnoughMoney($money)) {
            return;
        }
        $account->withdraw($money);
    }
}

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

এই পয়েন্টটি এমন একটি ভুল ধারণাও সম্বোধন করে যা আমি প্রায়শই এলএসপি লঙ্ঘনের বিষয়ে মুখোমুখি হই। এটি বলেছে যে "যদি কোনও সন্তানের মধ্যে পিতামাতার আচরণ পরিবর্তন হয় তবে তা এলএসপি লঙ্ঘন করে।" তবে, এটি তা নয় - যতক্ষণ না কোনও শিশু তার পিতামাতার চুক্তি লঙ্ঘন করে না।

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