হ্যাঁ, ওসিপি এবং এলএসপিতে কিছু অদ্ভুত ভুল ধারণা রয়েছে এবং কিছু কিছু পরিভাষা এবং বিভ্রান্তিকর উদাহরণগুলির মিল নেই। আপনি যদি একইভাবে প্রয়োগ করেন তবে উভয় নীতিই কেবল "একই জিনিস"। প্যাটার্নগুলি সাধারণত কিছু ব্যাতিক্রম সহ নীতিগুলি একরকম বা অন্য কোনও পথে অনুসরণ করে।
পার্থক্যগুলি আরও ব্যাখ্যা করা হবে তবে প্রথমে আসুন নীতির মধ্যে ডুব দেই:
উন্মুক্ত-বন্ধ নীতি (ওসিপি)
চাচা বব এর মতে :
আপনার কোনও শ্রেণিবিস্তার আচরণটি পরিবর্তন না করে প্রসারিত করতে সক্ষম হওয়া উচিত।
নোট করুন যে এই ক্ষেত্রে প্রসারিত শব্দের প্রয়োজনীয়তার অর্থ এই নয় যে আপনার আসল শ্রেণীর সাবক্লাস করা উচিত যা নতুন আচরণের প্রয়োজন। পরিভাষাটির প্রথম অমিলের সময়ে আমি কীভাবে উল্লেখ করেছি? extend
মূলশব্দটির অর্থ জাভাতে কেবল সাবক্লাসিং, তবে নীতিগুলি জাভার চেয়ে পুরানো।
মূলটি 1988 সালে বার্ট্র্যান্ড মেয়ারের কাছ থেকে এসেছে:
সফ্টওয়্যার সত্তা (শ্রেণি, মডিউল, ফাংশন, ইত্যাদি) এক্সটেনশনের জন্য উন্মুক্ত হওয়া উচিত, তবে পরিবর্তনের জন্য বন্ধ করা উচিত।
এখানে এটি আরও পরিষ্কার যে নীতিটি সফ্টওয়্যার সত্তাগুলিতে প্রয়োগ করা হয় । একটি খারাপ উদাহরণ সফ্টওয়্যার সত্তাকে ওভাররাইড করা হবে কারণ আপনি কিছুটা এক্সটেনশান সরবরাহের পরিবর্তে কোডটি পুরোপুরি পরিবর্তন করছেন। সফ্টওয়্যার সত্তাটির আচরণটি নিজেই বর্ধনযোগ্য হওয়া উচিত এবং এর একটি ভাল উদাহরণ কৌশল-প্যাটার্নের বাস্তবায়ন (কারণ এটি জিওএফ-প্যাটার্নগুলির গোছা আইএমএইচও-র প্রদর্শন করা সবচেয়ে সহজ):
// Context is closed for modifications. Meaning you are
// not supposed to change the code here.
public class Context {
// Context is however open for extension through
// this private field
private IBehavior behavior;
// The context calls the behavior in this public
// method. If you want to change this you need
// to implement it in the IBehavior object
public void doStuff() {
if (this.behavior != null)
this.behavior.doStuff();
}
// You can dynamically set a new behavior at will
public void setBehavior(IBehavior behavior) {
this.behavior = behavior;
}
}
// The extension point looks like this and can be
// subclassed/implemented
public interface IBehavior {
public void doStuff();
}
উপরের উদাহরণে Context
হয় লক আরও পরিবর্তন জন্য। বেশিরভাগ প্রোগ্রামাররা সম্ভবত বর্ধনের জন্য ক্লাসটি সাবক্লাস করতে চাইবে তবে এখানে আমরা এটি করি না কারণ এটি অনুমান করে যে এটির আচরণটি ইন্টারফেস প্রয়োগকারী কোনও কিছুর মাধ্যমে পরিবর্তন করা যেতে পারে IBehavior
।
অর্থাৎ প্রসঙ্গ শ্রেণিটি পরিবর্তনের জন্য বন্ধ থাকলেও এক্সটেনশনের জন্য উন্মুক্ত । এটি আসলে অন্য একটি মূল নীতি অনুসরণ করে কারণ আমরা উত্তরাধিকারের পরিবর্তে অবজেক্ট কম্পোজিশনের সাথে আচরণটি রাখছি:
"প্রিয় শ্রেণীর উত্তরাধিকারের উপর ' অবজেক্ট রচনা '। (গ্যাং অফ ফোর 1995: 20)
আমি পাঠককে সেই নীতিটি পড়তে দেব কারণ এটি এই প্রশ্নের ক্ষেত্রের বাইরে। উদাহরণ সহকারে চালিয়ে যেতে, বলুন আমাদের আইবিহেভিয়ার ইন্টারফেসের নিম্নলিখিত প্রয়োগ রয়েছে:
public class HelloWorldBehavior implements IBehavior {
public void doStuff() {
System.println("Hello world!");
}
}
public class GoodByeBehavior implements IBehavior {
public void doStuff() {
System.out.println("Good bye cruel world!");
}
}
এই প্যাটার্নটি ব্যবহার করে আমরা রানটাইমে প্রসঙ্গের আচরণটি setBehavior
এক্সটেনশন পয়েন্ট হিসাবে পদ্ধতিতে পরিবর্তন করতে পারি ।
// in your main method
Context c = new Context();
c.setBehavior(new HelloWorldBehavior());
c.doStuff();
// prints out "Hello world!"
c.setBehavior(new GoodByeBehavior());
c.doStuff();
// prints out "Good bye cruel world!"
সুতরাং আপনি যখনই "বদ্ধ" প্রসঙ্গ শ্রেণি প্রসারিত করতে চান, এটি "উন্মুক্ত" সহযোগিতা নির্ভরতা উপশ্রুত করে এটি করুন। এটি স্পষ্টতই প্রসঙ্গটি সাবক্লাসিংয়ের মতো নয় তবে এটি ওসিপি। এলএসপিও এই সম্পর্কে কোন উল্লেখ করে না।
উত্তরাধিকারের পরিবর্তে মিক্সিনগুলি দিয়ে প্রসারিত করা
সাবক্ল্যাসিং বাদে ওসিপি করার অন্যান্য উপায় রয়েছে। একটি উপায় হ'ল মিক্সিন ব্যবহারের মাধ্যমে আপনার ক্লাসগুলি এক্সটেনশনের জন্য উন্মুক্ত রাখা । ক্লাস-ভিত্তিক না হয়ে প্রোটোটাইপ-ভিত্তিক ভাষাগুলিতে এটি দরকারী। ধারণাটি হ'ল প্রয়োজন হিসাবে আরও পদ্ধতি বা বৈশিষ্ট্যগুলির সাথে একটি গতিশীল অবজেক্টটি সংশোধন করা হয়, অন্য কথায় যে বস্তুগুলি অন্য বস্তুর সাথে মিশ্রিত হয় বা "মিশ্রিত হয়" in
এখানে মিক্সিনের জাভাস্ক্রিপ্ট উদাহরণ যা অ্যাঙ্গরগুলির জন্য একটি সাধারণ এইচটিএমএল টেমপ্লেট রেন্ডার করে:
// The mixin, provides a template for anchor HTML elements, i.e. <a>
var LinkMixin = {
render: function() {
return '<a href="' + this.link +'">'
+ this.content
+ '</a>;
}
}
// Constructor for a youtube link
var YoutubeLink = function(content, youtubeId) {
this.content = content;
this.setLink(this.youtubeId);
};
// Methods are added to the prototype
YoutubeLink.prototype = {
setLink: function(youtubeid) {
this.link = 'http://www.youtube.com/watch?v=' + youtubeid;
}
};
// Extend YoutubeLink prototype with the LinkMixin using
// underscore/lodash extend
_.extend(YoutubeLink.protoype, LinkMixin);
// When used:
var ytLink = new YoutubeLink("Cool Movie!", "idOaZpX8lnA");
console.log(ytLink.render());
// will output:
// <a href="http://www.youtube.com/watch?=vidOaZpX8lnA">Cool Movie!</a>
ধারণাটি হ'ল বস্তুগুলিকে গতিময়ভাবে প্রসারিত করা এবং এর সুবিধা হ'ল বস্তুগুলি সম্পূর্ণ আলাদা ডোমেনে থাকলেও পদ্ধতিগুলি ভাগ করতে পারে। উপরের ক্ষেত্রে আপনি আপনার নির্দিষ্ট প্রয়োগটি এর সাথে প্রসারিত করে সহজেই অন্যান্য ধরণের এইচটিএমএল অ্যাঙ্কর তৈরি করতে পারেন LinkMixin
।
ওসিপির ক্ষেত্রে, "মিক্সিনগুলি" এক্সটেনশন। উপরের উদাহরণে YoutubeLink
আমাদের সফ্টওয়্যার সত্তাটি পরিবর্তনের জন্য বন্ধ রয়েছে তবে মিক্সিন ব্যবহারের মাধ্যমে এক্সটেনশনের জন্য উন্মুক্ত। অবজেক্টের শ্রেণিবিন্যাস সমতল করা হয়েছে যা প্রকারগুলি পরীক্ষা করা অসম্ভব করে তোলে। তবে এটি সত্যই খারাপ জিনিস নয় এবং আমি আরও নীচে ব্যাখ্যা করব যে প্রকারের জন্য চেক করা সাধারণত একটি খারাপ ধারণা এবং বহুরূপী ধারণার সাথে ধারণাটি ভেঙে দেয়।
মনে রাখবেন যে এই পদ্ধতিতে একাধিক উত্তরাধিকার সম্পাদন করা সম্ভব কারণ বেশিরভাগ extend
বাস্তবায়ন একাধিক বস্তুর মিশ্রণ করতে পারে:
_.extend(MyClass, Mixin1, Mixin2 /* [, ...] */);
আপনাকে কেবলমাত্র মনে রাখতে হবে নামগুলি সংঘর্ষ না করা, অর্থাত মিশ্রণগুলি কিছু বৈশিষ্ট্য বা পদ্ধতির একই নামটি সংজ্ঞায়িত করতে হবে কারণ সেগুলি ওভাররাইড হবে। আমার নম্র অভিজ্ঞতায় এটি একটি নন-ইস্যু এবং যদি এটি ঘটে তবে এটি ত্রুটিযুক্ত ডিজাইনের ইঙ্গিত।
লিসকভের সাবস্টিটিউশন নীতি (এলএসপি)
চাচা বব এটিকে সহজভাবে সংজ্ঞায়িত করেছেন:
উত্পন্ন ক্লাসগুলি অবশ্যই তাদের বেস ক্লাসের জন্য পরিবর্তনযোগ্য হতে হবে।
এই নীতিটি পুরানো, আসলে আঙ্কেল বব এর সংজ্ঞা নীতিগুলির মধ্যে পার্থক্য করে না কারণ এটি LSP এখনও ওসিপির সাথে নিবিড়ভাবে সম্পর্কিত করে তোলে যে উপরের কৌশলগত উদাহরণে একই সুপারটাইপ ব্যবহার করা হয় ( IBehavior
)। সুতরাং বারবারা লিসকভের এটির মূল সংজ্ঞাটি দেখতে দিন এবং দেখুন যে আমরা এই নীতিটি কোনও গাণিতিক উপপাদির মতো দেখতে অন্য কিছু খুঁজে পেতে পারি:
কি এখানে চেয়েছিলেন নিম্নলিখিত প্রতিকল্পন সম্পত্তি ভালো কিছু হল: প্রতিটি বস্তুর জন্য যদি o1
ধরনের S
একটি বস্তু আছে o2
ধরনের T
এমন সব প্রোগ্রামের জন্য যে P
পদ সংজ্ঞায়িত T
, আচরণকে P
অপরিবর্তিত যখন o1
প্রতিস্থাপিত হয় o2
তারপর S
একটি উপপ্রকার হয় T
।
কিছুক্ষণের জন্য এটিকে চলাফেরা করতে দেয়, লক্ষ্য করুন কারণ এটি ক্লাসের মোটেই উল্লেখ করে না। জাভাস্ক্রিপ্টে আপনি আসলে এলএসপি অনুসরণ করতে পারেন যদিও এটি স্পষ্টভাবে শ্রেণিবদ্ধ নয়। যদি আপনার প্রোগ্রামে জাভাস্ক্রিপ্ট অবজেক্টের কমপক্ষে কয়েকজনের একটি তালিকা থাকে যা:
- একইভাবে গণনা করা দরকার,
- একই আচরণ, এবং
- অন্যথায় কোনওভাবে সম্পূর্ণ ভিন্ন
... তারপরে অবজেক্টগুলিকে একই "টাইপ" বলে মনে করা হয় এবং প্রোগ্রামটির জন্য এটি আসলে কোনও বিষয় নয়। এটি মূলত বহুপদীতা । জেনেরিক অর্থে; আপনি যদি এটি ইন্টারফেস ব্যবহার করছেন তবে আপনার প্রকৃত উপপ্রকারটি জানা উচিত নয়। ওসিপি এ বিষয়ে সুস্পষ্ট কিছু বলেনি। এটি আসলে বেশিরভাগ নবজাতক প্রোগ্রামারদের করা একটি ডিজাইনের ভুলটিকেও নির্দেশ করে:
যখনই আপনি কোনও জিনিসের সাব টাইপ পরীক্ষা করার তাগিদ অনুভব করছেন, আপনি সম্ভবত এটি ভুল করেছেন।
ঠিক আছে, তাই এটি সর্বদা ভুল নাও হতে পারে তবে আপনার যদি এনাম বা এনামদের সাথে কিছু প্রকারের চেক করার তাগিদ থাকে তবে আপনি instanceof
নিজের জন্য প্রোগ্রামটির প্রয়োজনের চেয়ে কিছুটা বিশৃঙ্খলা করছেন। তবে এটি সবসময় হয় না; জিনিসগুলি কাজ করার জন্য দ্রুত এবং নোংরা হ্যাকগুলি মনে মনে সমাধান করা ঠিক আছে যদি সমাধানটি যথেষ্ট পরিমাণে ছোট হয় এবং আপনি যদি নির্দয় পুনর্নির্মাণের অনুশীলন করেন , তবে পরিবর্তনগুলি যখন এটির দাবি করেছে তখন এটি উন্নত হতে পারে।
আসল সমস্যার উপর নির্ভর করে এই "ডিজাইন ভুল" এর চারপাশে উপায় রয়েছে:
- সুপার ক্লাস পূর্বশর্তগুলি কল করছে না, পরিবর্তে কলকারীকে এটি করতে বাধ্য করছে।
- সুপার ক্লাসে কলকারীটির প্রয়োজনীয় একটি জেনেরিক পদ্ধতি অনুপস্থিত।
এই দুটিই সাধারণ কোড ডিজাইন "ভুল"। আপনি করতে পারেন এমন কয়েকটি পৃথক রিফ্যাক্টরিং রয়েছে, যেমন টান-আপ পদ্ধতি , বা ভিজিটর প্যাটার্নের কোনও ধরণের রিফ্যাক্টর ।
আমি আসলে ভিজিটর প্যাটার্নটি অনেক পছন্দ করি কারণ এটি যদি ইফ-স্টেটমেন্ট স্প্যাগেটির বড় যত্ন নিতে পারে এবং আপনি বিদ্যমান কোডটিতে যা ভাবেন তার চেয়ে এটি কার্যকর করা সহজ। বলুন আমাদের নীচের প্রসঙ্গ রয়েছে:
public class Context {
public void doStuff(string query) {
// outcome no. 1
if (query.Equals("Hello")) {
System.out.println("Hello world!");
}
// outcome no. 2
else if (query.Equals("Bye")) {
System.out.println("Good bye cruel world!");
}
// a change request may require another outcome...
}
}
// usage:
Context c = new Context();
c.doStuff("Hello");
// prints "Hello world"
c.doStuff("Bye");
// prints "Bye"
ইফ-বিবৃতিটির ফলাফলগুলি তাদের নিজস্ব দর্শকদের মধ্যে অনুবাদ করা যায় কারণ প্রত্যেকে কিছু সিদ্ধান্ত এবং কিছু কোড চালনার উপর নির্ভর করে। আমরা এটির মতো এটি বের করতে পারি:
public interface IVisitor {
public bool canDo(string query);
public void doStuff();
}
// outcome 1
public class HelloVisitor implements IVisitor {
public bool canDo(string query) {
return query.Equals("Hello");
}
public void doStuff() {
System.out.println("Hello World");
}
}
// outcome 2
public class ByeVisitor implements IVisitor {
public bool canDo(string query) {
return query.Equals("Bye");
}
public void doStuff() {
System.out.println("Good bye cruel world");
}
}
এই মুহুর্তে, প্রোগ্রামার যদি ভিজিটর প্যাটার্ন সম্পর্কে জানতে না পারে, তবে তিনি প্রসঙ্গটি ক্লাসটি কিছু নির্দিষ্ট ধরণের কিনা তা পরীক্ষা করার জন্য প্রয়োগ করতেন। ভিজিটর ক্লাসগুলির একটি বুলিয়ান canDo
পদ্ধতি রয়েছে, তাই বাস্তবায়নকারী সেই পদ্ধতি কলটি ব্যবহার করে এটি কাজ করার সঠিক বিষয় কিনা তা নির্ধারণ করতে পারেন। প্রসঙ্গ শ্রেণি সমস্ত দর্শনার্থী (এবং নতুন যুক্ত করতে) এর মতো ব্যবহার করতে পারে:
public class Context {
private ArrayList<IVisitor> visitors = new ArrayList<IVisitor>();
public Context() {
visitors.add(new HelloVisitor());
visitors.add(new ByeVisitor());
}
// instead of if-statements, go through all visitors
// and use the canDo method to determine if the
// visitor object is the right one to "visit"
public void doStuff(string query) {
for(IVisitor visitor : visitors) {
if (visitor.canDo(query)) {
visitor.doStuff();
break;
// or return... it depends if you have logic
// after this foreach loop
}
}
}
// dynamically adds new visitors
public void addVisitor(IVisitor visitor) {
if (visitor != null)
visitors.add(visitor);
}
}
উভয় নিদর্শনগুলি ওসিপি এবং এলএসপিকে অনুসরণ করে, তবে তারা উভয়ই তাদের সম্পর্কে বিভিন্ন বিষয় নির্দেশ করে। সুতরাং কোডটি যদি নীতিগুলির মধ্যে একটি লঙ্ঘন করে তবে এর মতো দেখতে কেমন?
একটি নীতি লঙ্ঘন কিন্তু অন্য অনুসরণ
নীতিগুলির একটি ভঙ্গ করার উপায় রয়েছে তবে এখনও অন্যটি অনুসরণ করা যেতে পারে। নীচের উদাহরণগুলি যথাযথ কারণে সংশ্লেষিত বলে মনে হচ্ছে, তবে আমি প্রকৃতপক্ষে এগুলি উত্পাদন কোডে পপিং করতে দেখেছি (এবং আরও খারাপ):
ওসিপি অনুসরণ করে তবে এলএসপি অনুসরণ করে না
যাক আমাদের দেওয়া কোডটি আছে:
public interface IPerson {}
public class Boss implements IPerson {
public void doBossStuff() { ... }
}
public class Peon implements IPerson {
public void doPeonStuff() { ... }
}
public class Context {
public Collection<IPerson> getPersons() { ... }
}
এই কোডের টুকরোটি মুক্ত-বদ্ধ নীতি অনুসরণ করে। আমরা যদি প্রসঙ্গের GetPersons
পদ্ধতিটি কল করি তবে আমরা তাদের নিজস্ব বাস্তবায়ন সহ একগুচ্ছ ব্যক্তি পেয়ে যাব। এর অর্থ এই যে আইফারসন পরিবর্তনের জন্য বন্ধ রয়েছে, তবে এক্সটেনশনের জন্য উন্মুক্ত। তবে বিষয়গুলি যখন আমাদের এটি ব্যবহার করতে হয় তখন একটি অন্ধকার মোড় নেয়:
// in some routine that needs to do stuff with
// a collection of IPerson:
Collection<IPerson> persons = context.getPersons();
for (IPerson person : persons) {
// now we have to check the type... :-P
if (person instanceof Boss) {
((Boss) person).doBossStuff();
}
else if (person instanceof Peon) {
((Peon) person).doPeonStuff();
}
}
আপনাকে টাইপ চেকিং করতে হবে এবং রূপান্তর টাইপ করতে হবে! মনে রাখবেন যে আমি উপরে উল্লেখ করেছি কীভাবে টাইপ চেকিং একটি খারাপ জিনিস ? ওহ না! তবে ভয় পাবেন না, যেমন উপরে উল্লিখিত হয় হয় কিছু পুল-আপ রিফ্যাক্টরিং করে বা কোনও দর্শনার্থীর প্যাটার্ন প্রয়োগ করে। এক্ষেত্রে একটি সাধারণ পদ্ধতি যুক্ত করার পরে আমরা কেবল একটি পুল আপ রিফ্যাক্টরিং করতে পারি:
public class Boss implements IPerson {
// we're adding this general method
public void doStuff() {
// that does the call instead
this.doBossStuff();
}
public void doBossStuff() { ... }
}
public interface IPerson {
// pulled up method from Boss
public void doStuff();
}
// do the same for Peon
এখন সুবিধাটি হ'ল এলএসপিকে অনুসরণ করে আপনার আর সঠিক ধরণেরটি জানতে হবে না:
// in some routine that needs to do stuff with
// a collection of IPerson:
Collection<IPerson> persons = context.getPersons();
for (IPerson person : persons) {
// yay, no type checking!
person.doStuff();
}
এলএসপি অনুসরণ করে তবে ওসিপি নয়
আসুন এমন কোনও কোড দেখুন যা এলএসপি অনুসরণ করে তবে ওসিপি নয়, এটি একধরনের বিষয়বস্তুযুক্ত তবে আমার এটি সহ্য করুন এটি খুব সূক্ষ্ম ভুল:
public class LiskovBase {
public void doStuff() {
System.out.println("My name is Liskov");
}
}
public class LiskovSub extends LiskovBase {
public void doStuff() {
System.out.println("I'm a sub Liskov!");
}
}
public class Context {
private LiskovBase base;
// the good stuff
public void doLiskovyStuff() {
base.doStuff();
}
public void setBase(LiskovBase base) { this.base = base }
}
কোডটি এলএসপি করে কারণ প্রসঙ্গটি প্রকৃত প্রকারটি না জেনে লিসকভবেস ব্যবহার করতে পারে। আপনি কি ভাববেন যে এই কোডটি ওসিপি অনুসরণ করে তবে ঘনিষ্ঠভাবে দেখুন, ক্লাসটি কি সত্যিই বন্ধ রয়েছে ? doStuff
পদ্ধতিটি যদি কেবল একটি লাইন প্রিন্ট করার চেয়ে আরও বেশি কিছু করে?
: উত্তর যদি এটা OCP অনুসরণ সহজভাবে হয় কোন কারণ এই বস্তু নকশা আমরা অন্য কিছু সাথে সম্পূর্ণরূপে কোড ওভাররাইড করতে হয় না,। কাজগুলি করার জন্য বেস ক্লাস থেকে আপনার কোডটি অনুলিপি করতে হওয়ায় এটি কীটগুলির কাট-পেস্টের ক্যান খুলতে পারে। doStuff
পদ্ধতি নিশ্চিত এক্সটেনশন জন্য খোলা, কিন্তু এটা সম্পূর্ণরূপে পরিবর্তন জন্য বন্ধ করা হয় নি।
আমরা এটিতে টেম্পলেট পদ্ধতি প্যাটার্ন প্রয়োগ করতে পারি । টেমপ্লেট পদ্ধতির প্যাটার্ন ফ্রেমওয়ার্কগুলিতে এতটাই সাধারণ যে আপনি এটি না জেনেও এটি ব্যবহার করে থাকতে পারেন (যেমন জাভা সুইং উপাদানগুলি, সি # ফর্ম এবং উপাদানগুলি ইত্যাদি)। doStuff
জাভা final
কীওয়ার্ড দিয়ে চিহ্নিত করে এটি বন্ধ থাকার বিষয়টি নিশ্চিত করার এবং পদ্ধতিটি বন্ধ করার একটি উপায় এখানে Here এই কীওয়ার্ডটি ক্লাসকে আরও সাবক্লাসিং থেকে আরও বাধা দেয় (সি # তে আপনি sealed
একই জিনিসটি ব্যবহার করতে পারেন )।
public class LiskovBase {
// this is now a template method
// the code that was duplicated
public final void doStuff() {
System.out.println(getStuffString());
}
// extension point, the code that "varies"
// in LiskovBase and it's subclasses
// called by the template method above
// we expect it to be virtual and overridden
public string getStuffString() {
return "My name is Liskov";
}
}
public class LiskovSub extends LiskovBase {
// the extension overridden
// the actual code that varied
public string getStuffString() {
return "I'm sub Liskov!";
}
}
এই উদাহরণটি ওসিপি অনুসরণ করে এবং নির্বোধ বলে মনে হয়, এটি হ'ল তবে হ্যান্ডেল করার জন্য আরও কোড দিয়ে এটিকে ছোট করে দেখুন। আমি উত্পাদনে মোতায়েন থাকা কোড দেখতে পাচ্ছি যেখানে সাবক্লাসগুলি সম্পূর্ণরূপে সমস্ত কিছু ওভাররাইড করে এবং ওভাররাইড কোডটি বেশিরভাগ প্রয়োগের মধ্যে কাট-এন-পেস্ট করা হয়। এটি কাজ করে, তবে সমস্ত কোডের সাথে ডুপ্লিকেশনও রক্ষণাবেক্ষণের দুঃস্বপ্নগুলির জন্য একটি সেট আপ।
উপসংহার
আমি আশা করি এটি সমস্তই ওসিপি এবং এলএসপি এবং তাদের মধ্যে পার্থক্য / সাদৃশ্য সম্পর্কিত কিছু প্রশ্ন মুছে ফেলে। এগুলিকে সমান হিসাবে বরখাস্ত করা সহজ তবে উপরের উদাহরণগুলিতে দেখানো উচিত যে তারা তা নয়।
নোট করুন, উপরে নমুনা কোড থেকে সংগ্রহ:
ওসিপি কার্যকরী কোডটি লক করার বিষয়ে রয়েছে তবে এটি কোনও প্রকারের এক্সটেনশন পয়েন্টগুলির সাথে কোনওভাবে খোলা রাখবে।
এটি হ'ল টেমপ্লেট পদ্ধতিটির প্যাটার্নের উদাহরণ হিসাবে কোড পরিবর্তন করে কোড নকল করে এড়ানো। এটি দ্রুত ব্যর্থ হওয়ার জন্য যেমন ব্রেকিং পরিবর্তনগুলি বেদনাদায়ক হয় (যেমন একটি জায়গা পরিবর্তন করুন, এটিকে অন্য কোথাও ভাঙ্গুন) মঞ্জুরি দেয়। রক্ষণাবেক্ষণের প্রয়োজনে এনক্যাপসুলেটিং পরিবর্তনের ধারণাটি একটি ভাল জিনিস, কারণ পরিবর্তনগুলি সর্বদা ঘটে।
এলএসপি ব্যবহারকারীকে বিভিন্ন বস্তু পরিচালনা করতে দেয় যা প্রকৃত ধরনটি কী তা পরীক্ষা না করে সুপারটাইপ প্রয়োগ করে। পলিমারফিজমটি সহজাতভাবে এটি ।
এই নীতিটি টাইপ-চেকিং এবং টাইপ-রূপান্তর করার বিকল্প সরবরাহ করে, যা প্রকারের সংখ্যা বাড়ার সাথে সাথে হাতছাড়া হয়ে যেতে পারে এবং ভিজিটরের মতো টান-আপ রিফ্যাক্টরিং বা প্রয়োগ করার মাধ্যমে এটি অর্জন করা যেতে পারে।