সুতরাং, স্পষ্টভাবে একটি ইন্টারফেস বাস্তবায়নের জন্য ভাল ব্যবহারের ক্ষেত্রে কী?
ক্লাস ব্যবহারকারী লোকদের ইন্টেলিসেন্সে all সমস্ত পদ্ধতি / বৈশিষ্ট্যগুলি দেখার দরকার নেই তা কেবল তাই?
সুতরাং, স্পষ্টভাবে একটি ইন্টারফেস বাস্তবায়নের জন্য ভাল ব্যবহারের ক্ষেত্রে কী?
ক্লাস ব্যবহারকারী লোকদের ইন্টেলিসেন্সে all সমস্ত পদ্ধতি / বৈশিষ্ট্যগুলি দেখার দরকার নেই তা কেবল তাই?
উত্তর:
আপনি যদি একই পদ্ধতি এবং বিভিন্ন বাস্তবায়ন উভয়ই দুটি ইন্টারফেস প্রয়োগ করেন তবে আপনাকে সুস্পষ্টভাবে বাস্তবায়ন করতে হবে।
public interface IDoItFast
{
void Go();
}
public interface IDoItSlow
{
void Go();
}
public class JustDoIt : IDoItFast, IDoItSlow
{
void IDoItFast.Go()
{
}
void IDoItSlow.Go()
{
}
}
অ-পছন্দসই সদস্যটিকে আড়াল করতে এটি দরকারী। উদাহরণস্বরূপ, যদি আপনি উভয়ই বাস্তবায়ন করেন IComparable<T>এবং লোকেদের বোঝা না দেয় যে আপনি বিভিন্ন ধরণের অবজেক্টের তুলনা করতে পারেন IComparableতবে সাধারণত ওভারলোডটি আড়াল করা খুব ভাল IComparable। একইভাবে, কিছু ইন্টারফেস সিএলএস-সম্মতিযুক্ত নয়, যেমন IConvertible, তাই যদি আপনি স্পষ্টভাবে ইন্টারফেসটি প্রয়োগ না করেন, তবে সিএলএস সম্মতি প্রয়োজন এমন ভাষার শেষ ব্যবহারকারীরা আপনার অবজেক্টটি ব্যবহার করতে পারবেন না। (ছাত্রলীগের প্রয়োগকারীরা আদিমদের আইকনভার্টেবল সদস্যদের গোপন না রাখলে খুব বিপর্যয়কর হবে :))
আর একটি আকর্ষণীয় নোট হ'ল সাধারণত এই জাতীয় নির্মাণ ব্যবহার করা মানে এমন কাঠামো যা স্পষ্টভাবে একটি ইন্টারফেস প্রয়োগ করে কেবল ইন্টারফেসের ধরণের বক্সিং করেই তাদের ডেকে আনতে পারে। জেনেরিক সীমাবদ্ধতা ব্যবহার করে আপনি এটি পেতে পারেন ::
void SomeMethod<T>(T obj) where T:IConvertible
আপনি যখন এটি পাস করেন তখন কোনও ইন্টার বক্স করবে না।
stringজেনেরিকগুলির আগে প্রায় ছিল এবং এই অনুশীলন প্রচলিত ছিল। .NET 2 যখন এলো তখন তারা জনসাধারণের ইন্টারফেসটি ভেঙে ফেলতে চায়নি stringতাই তারা এটি নিরাপদে রক্ষণাবেক্ষণের সাথে রেখেছিল around
স্পষ্টভাবে একটি ইন্টারফেস বাস্তবায়ন করার জন্য কিছু অতিরিক্ত কারণ:
পিছনে সামঞ্জস্যতা : ICloneableইন্টারফেস পরিবর্তনের ক্ষেত্রে , প্রয়োগকারী পদ্ধতি শ্রেণীর সদস্যদের তাদের পদ্ধতি স্বাক্ষর পরিবর্তন করতে হবে না।
ক্লিনার কোড : Cloneপদ্ধতিটি আইক্লোনেবল থেকে অপসারণ করা হলে একটি সংকলক ত্রুটি থাকবে, তবে আপনি যদি পদ্ধতিটি স্পষ্টভাবে প্রয়োগ করেন তবে অব্যক্ত 'অনাথ' পাবলিক পদ্ধতিতে শেষ করতে পারেন
দৃ strong ় টাইপিং : সুপারকার্টের একটি উদাহরণ উদাহরণ সহকারে বর্ণনা করার জন্য, এটি আমার পছন্দসই নমুনা কোড হবে, আপনি যখন উদাহরণস্বরূপ সদস্য হিসাবে সরাসরি ডাকেন তখন ICloneableস্পষ্টভাবে প্রয়োগ করা দৃ Clone()strongly়ভাবে টাইপ করার অনুমতি দেয় MyObject:
public class MyObject : ICloneable
{
public MyObject Clone()
{
// my cloning logic;
}
object ICloneable.Clone()
{
return this.Clone();
}
}
interface ICloneable<out T> { T Clone(); T self {get;} }। লক্ষ্য করুন যে ICloneable<T>টি-তে ইচ্ছাকৃত কোনও বাধা নেই, যদিও কোনও বস্তু সাধারণত কেবল তার ভিত্তি হতে পারে তবে নিরাপদে ক্লোন করা যায় তবে যে কোনও শ্রেণীর অবজেক্টকে নিরাপদে ক্লোন করা যায় এমন কোনও বেস ক্লাস থেকে উদ্ভব করতে পারে। এটির জন্য অনুমতি দেওয়ার জন্য, আমি উত্তরাধিকারসূত্রে ক্লাস করার জন্য একটি পাবলিক ক্লোন পদ্ধতি প্রকাশের বিরুদ্ধে সুপারিশ করব। পরিবর্তে protectedক্লোনিং পদ্ধতি এবং সিল করা ক্লাস সহ উত্তরাধিকারসূত্রে ক্লাস রয়েছে যা সেগুলি থেকে প্রাপ্ত এবং পাবলিক ক্লোনিং প্রকাশ করে।
আর একটি দরকারী কৌশল হ'ল কোনও ফাংশনের জনসাধারণের প্রয়োগের একটি পদ্ধতিতে এমন একটি মান ফেরত দেওয়া যা কোনও ইন্টারফেসে নির্দিষ্ট চেয়ে নির্দিষ্ট।
উদাহরণস্বরূপ, কোনও অবজেক্ট বাস্তবায়ন করতে পারে ICloneableতবে এর সর্বজনীনভাবে দৃশ্যমানClone পদ্ধতিটি তার নিজস্ব প্রকারটি ফেরত দিতে পারে।
তেমনি, একটি পদ্ধতি এমন IAutomobileFactoryএকটি Manufactureপদ্ধতি থাকতে পারে যা একটি ফেরত দেয় Automobile, তবে ক FordExplorerFactory, যা প্রয়োগ করে IAutomobileFactory, তার Manufactureপদ্ধতিটি একটি FordExplorer(যা থেকে প্রাপ্ত Automobile) ফিরে আসতে পারে । কোড যা জানে যে এটিতে কোনও টাইপকাস্ট না করে ফিরিয়ে দেওয়া কোনও বস্তুর উপর একটি নির্দিষ্ট বৈশিষ্ট্য FordExplorerFactoryব্যবহার করা যেতে পারে , যখন কোডটি কেবলমাত্র জানত যে এটির কোনও প্রকারেরটি কেবল এটি হিসাবে তার প্রত্যাবর্তনকে মোকাবেলা করবে ।FordExplorerFordExplorerFactoryIAutomobileFactoryAutomobile
একই সদস্যের নাম এবং স্বাক্ষরের সাথে আপনার দুটি ইন্টারফেস থাকলে এটি কার্যকর হয় তবে এটি কীভাবে ব্যবহৃত হয় তার উপর নির্ভর করে এর আচরণ পরিবর্তন করতে চাই। (আমি এই জাতীয় কোড লেখার প্রস্তাব দিই না):
interface Cat
{
string Name {get;}
}
interface Dog
{
string Name{get;}
}
public class Animal : Cat, Dog
{
string Cat.Name
{
get
{
return "Cat";
}
}
string Dog.Name
{
get
{
return "Dog";
}
}
}
static void Main(string[] args)
{
Animal animal = new Animal();
Cat cat = animal; //Note the use of the same instance of Animal. All we are doing is picking which interface implementation we want to use.
Dog dog = animal;
Console.WriteLine(cat.Name); //Prints Cat
Console.WriteLine(dog.Name); //Prints Dog
}
public class Animal : Cat, Dog
এটি কোনও ইন্টারফেসকে স্পষ্টভাবে প্রয়োগ করতে পাবলিক ইন্টারফেস ক্লিনার রাখতে পারে, অর্থাত আপনার Fileক্লাসটি IDisposableস্পষ্টভাবে প্রয়োগ করতে পারে এবং এমন একটি পাবলিক পদ্ধতি প্রদান Close()করতে পারে যা কোনও গ্রাহকের চেয়ে বেশি বোঝায় Dispose(।
F # কেবল স্পষ্টত ইন্টারফেস প্রয়োগের প্রস্তাব দেয় যাতে আপনার কার্যকারিতা অ্যাক্সেস করার জন্য আপনাকে সর্বদা নির্দিষ্ট ইন্টারফেসে কাস্ট করতে হয়, যা ইন্টারফেসটির খুব স্পষ্ট (কোনও পাং উদ্দেশ্যে নয়) ব্যবহার করে।
Disposeসেগুলি যা কখনও পরিষ্কারের প্রয়োজন হবে না); এর চেয়ে উত্তম উদাহরণ হ'ল অপরিবর্তনীয় সংগ্রহের বাস্তবায়নের মতো কিছু IList<T>.Add।
আপনার যদি অভ্যন্তরীণ ইন্টারফেস থাকে এবং আপনি আপনার শ্রেণিতে সদস্যদের প্রকাশ্যে প্রয়োগ করতে চান না, আপনি তাদের স্পষ্টভাবে প্রয়োগ করবেন। অন্তর্নিহিত বাস্তবায়নগুলি জনসাধারণের প্রয়োজন।
সুস্পষ্ট বাস্তবায়নের আরেকটি কারণ রক্ষণাবেক্ষণযোগ্যতা ।
যখন কোনও শ্রেণি "ব্যস্ত" হয়ে যায় - হ্যাঁ এটি হয়ে যায়, আমাদের সকলেরই অন্যান্য দলের সদস্যদের কোডটি রিফ্যাক্ট করার বিলাসিতা নেই - তারপরে একটি সুস্পষ্ট প্রয়োগের ফলে এটি স্পষ্ট হয়ে যায় যে কোনও ইন্টারফেস চুক্তি পূরণের জন্য কোনও পদ্ধতি রয়েছে।
সুতরাং এটি কোডের "পঠনযোগ্যতা" উন্নত করে।
#regionজন্য, এক্ষেত্রে তারা চুক্তিটি পূরণ করে - উপযুক্ত শিরোনামের স্ট্রিং সহ যা যা হয় তা ঠিক করে। এবং পদ্ধতি সম্পর্কে একটি মন্তব্য।
একটি ভিন্ন উদাহরণ দেওয়া হয় System.Collections.Immutable , এতে লেখকরা সংগ্রহের ধরণের জন্য একটি পরিচিত API সংরক্ষণের জন্য কৌশলটি ব্যবহার করার পছন্দ করেছেন যখন ইন্টারফেসের অংশগুলি তাদের নতুন ধরণের জন্য কোনও অর্থ রাখে না।
Concretely, ImmutableList<T>কার্যকরী IList<T>এবং এইভাবে ICollection<T>( অনুক্রমে করার অনুমতি ImmutableList<T>এখনো, উত্তরাধিকার কোড সহ আরও সহজে ব্যবহার করা হবে) void ICollection<T>.Add(T item)একটি জন্য কোন জ্ঞান করে তোলে ImmutableList<T>একটি অপরিবর্তনীয় লিস্টে একটি উপাদান যোগ বিদ্যমান তালিকায় পরিবর্তন করা উচিত নয়, যেহেতু: ImmutableList<T>এছাড়াও আহরিত থেকে IImmutableList<T>যার IImmutableList<T> Add(T item)ব্যবহার করা যেতে পারে অপরিবর্তনীয় তালিকা
সুতরাং, ক্ষেত্রে নিম্নলিখিত হিসাবে শেষ পর্যন্ত Addবাস্তবায়নগুলি ImmutableList<T>:
public ImmutableList<T> Add(T item)
{
// Create a new list with the added item
}
IImmutableList<T> IImmutableList<T>.Add(T value) => this.Add(value);
void ICollection<T>.Add(T item) => throw new NotSupportedException();
int IList.Add(object value) => throw new NotSupportedException();
সুস্পষ্টভাবে সংজ্ঞায়িত ইন্টারফেসের ক্ষেত্রে, সমস্ত পদ্ধতি স্বয়ংক্রিয়ভাবে ব্যক্তিগত হয়, আপনি এগুলিতে অ্যাক্সেস মডিফায়ারটিকে সর্বজনীন দিতে পারবেন না। ধরুন:
interface Iphone{
void Money();
}
interface Ipen{
void Price();
}
class Demo : Iphone, Ipen{
void Iphone.Money(){ //it is private you can't give public
Console.WriteLine("You have no money");
}
void Ipen.Price(){ //it is private you can't give public
Console.WriteLine("You have to paid 3$");
}
}
// So you have to cast to call the method
class Program
{
static void Main(string[] args)
{
Demo d = new Demo();
Iphone i1 = (Iphone)d;
i1.Money();
((Ipen)i1).Price();
Console.ReadKey();
}
}
// You can't call methods by direct class object
আমরা এভাবেই স্পষ্টত ইন্টারফেস তৈরি করতে পারি: আমাদের যদি দুটি ইন্টারফেস থাকে এবং উভয় ইন্টারফেসের একই পদ্ধতি থাকে এবং একটি একক শ্রেণীর এই 2 টি ইন্টারফেসের উত্তরাধিকারী হয় তাই যখন আমরা একটি ইন্টারফেস পদ্ধতি বলি তখন কম্পাইলারটি কোন পদ্ধতিটি কল করতে হবে তা বিভ্রান্ত হয়ে যায়, তাই আমরা পারি সুস্পষ্ট ইন্টারফেস ব্যবহার করে এই সমস্যাটি পরিচালনা করুন। আমি নীচে দেওয়া একটি উদাহরণ এখানে।
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace oops3
{
interface I5
{
void getdata();
}
interface I6
{
void getdata();
}
class MyClass:I5,I6
{
void I5.getdata()
{
Console.WriteLine("I5 getdata called");
}
void I6.getdata()
{
Console.WriteLine("I6 getdata called");
}
static void Main(string[] args)
{
MyClass obj = new MyClass();
((I5)obj).getdata();
Console.ReadLine();
}
}
}