কেন একটি বর্গ উত্তরাধিকারী এবং সম্পত্তি যুক্ত না?


39

আমি আমাদের (বরং বৃহত্তর) কোড বেসে উত্তরাধিকারী গাছ পেয়েছি যা এরকম কিছু হয়:

public class NamedEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class OrderDateInfo : NamedEntity { }

আমি যা জড়ো করতে পারি তা থেকে এটি মূলত ফ্রন্ট-এন্ডে স্ট্যান্ড বাঁধতে ব্যবহৃত হয়।

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

এই পদ্ধতির কোনও ডাউনসাইড রয়েছে?


25
ওলট উল্লেখ না: আপনি পদ্ধতি শুধুমাত্র সাথে প্রাসঙ্গিক আলাদা করতে পারেন OrderDateInfoযে অন্যান্য সাথে প্রাসঙ্গিক থেকে গুলি NamedEntityগুলি
Caleth

8
একই কারণে আপনি যদি বলেন যে, একটি Identifierশ্রেণীর সাথে কিছুই করার নেই NamedEntityতবে একটি সম্পত্তি Idএবং Nameসম্পত্তি উভয়ই প্রয়োজন , আপনি NamedEntityপরিবর্তে ব্যবহার করবেন না । শ্রেণীর প্রসঙ্গ এবং যথাযথ ব্যবহার হ'ল বৈশিষ্ট্য এবং পদ্ধতিগুলির চেয়ে বেশি যা এটি ধারণ করে।
নীল

উত্তর:


15

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

এই পদ্ধতির কোনও ডাউনসাইড রয়েছে?

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

উদাহরণস্বরূপ, বিবেচনা করুন যে আপনি সত্তার নাম দিয়েছেন এবং অডিটেড সত্তা। আপনার কয়েকটি সত্ত্বা রয়েছে:

Oneনিরীক্ষিত সত্তা বা নামযুক্ত সত্তা নয়। এটি সহজ:

public class One 
{ }

Twoনামযুক্ত সত্তা তবে নিরীক্ষিত সত্তা নয়। এটি আপনার কাছে এখন মূলত:

public class NamedEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Two : NamedEntity 
{ }

Threeউভয় একটি নামযুক্ত এবং নিরীক্ষিত এন্ট্রি। এখানেই আপনি কোনও সমস্যায় পড়েছেন। আপনি একটি AuditedEntityবেস শ্রেণি তৈরি করতে পারেন , তবে আপনি উভয়ইThree উত্তরাধিকারী করতে পারবেন না এবং : AuditedEntity NamedEntity

public class AuditedEntity
{
    public DateTime CreatedOn { get; set; }
    public DateTime UpdatedOn { get; set; }
}

public class Three : NamedEntity, AuditedEntity  // <-- Compiler error!
{ }

যাইহোক, আপনি AuditedEntityউত্তরাধিকারসূত্রে থাকার দ্বারা একটি workaround চিন্তা করতে পারেন NamedEntity। এটি নিশ্চিত করার জন্য এটি একটি চালাক হ্যাক যা প্রতিটি শ্রেণীর কেবলমাত্র অন্য কোনও শ্রেণীর থেকে উত্তরাধিকারী (সরাসরি) হওয়া দরকার।

public class AuditedEntity : NamedEntity
{
    public DateTime CreatedOn { get; set; }
    public DateTime UpdatedOn { get; set; }
}

public class Three : AuditedEntity
{ }

এটি এখনও কাজ করে। তবে আপনি এখানে যা করেছেন তা উল্লেখ করা হয়েছে যে প্রতিটি নিরীক্ষিত সত্তা সহজাতভাবে একটি নামকৃত সত্তাও । যা আমার শেষ উদাহরণে নিয়ে আসে। Fourনিরীক্ষিত সত্তা তবে নামযুক্ত সত্তা নয়। তবে আপনি অডিটডেন্টিটি নেমটেইনটি` এর মধ্যে উত্তরাধিকারের কারণে এটিকে Fourউত্তরাধিকার সূত্রে পরিণত করতে পারবেন না `AuditedEntityNamedEntityand

উত্তরাধিকার ব্যবহার করে, দু'টি তৈরি করার Threeএবং Fourকাজ করার কোনও উপায় নেই যতক্ষণ না আপনি অনুলিপি ক্লাসগুলি শুরু করেন (যা সমস্যার সম্পূর্ণ নতুন সেট উন্মুক্ত করে)।

ইন্টারফেস ব্যবহার করে, এটি সহজেই অর্জন করা যায়:

public interface INamedEntity
{
    int Id { get; set; }
    string Name { get; set; }
}

public interface IAuditedEntity
{
    DateTime CreatedOn { get; set; }
    DateTime UpdatedOn { get; set; }
}

public class One 
{ }

public class Two : INamedEntity 
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Three : INamedEntity, IAuditedEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    DateTime CreatedOn { get; set; }
    DateTime UpdatedOn { get; set; }
}

public class Four : IAuditedEntity
{
    DateTime CreatedOn { get; set; }
    DateTime UpdatedOn { get; set; }
}

এখানে কেবলমাত্র ছোটখাটো ব্যর্থতা হ'ল আপনাকে এখনও ইন্টারফেসটি প্রয়োগ করতে হবে। আপনি যখন কোনও নির্দিষ্ট সত্তার জন্য একাধিক সাধারণ ধরণের পরিবর্তনের প্রয়োজন হয় তখন কোনও পুনরায় ব্যবহারযোগ্য টাইপ না করেই আপনি সমস্ত সুবিধা পান।

তবে আপনার বহুত্ববাদ অটুট রয়েছে:

var one = new One();
var two = new Two();
var three = new Three();
var four = new Four();

public void HandleNamedEntity(INamedEntity namedEntity) {}
public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}

HandleNamedEntity(one);    //Error - not a named entity
HandleNamedEntity(two);
HandleNamedEntity(three);  
HandleNamedEntity(four);   //Error - not a named entity

HandleAuditedEntity(one);    //Error - not an audited entity
HandleAuditedEntity(two);    //Error - not an audited entity
HandleAuditedEntity(three);  
HandleAuditedEntity(four);

অন্যদিকে, এমন অনেকগুলি ক্লাস রয়েছে যার কেবল কোনও অতিরিক্ত সম্পত্তি নেই।

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

ফেস ভ্যালুতে, চিহ্নিতকারী ইন্টারফেস / ক্লাসগুলির সাথে কোনও ভুল নেই। এগুলি সিনট্যাক্টিক্যালি এবং টেকনিক্যালি বৈধ এবং এগুলি ব্যবহারের ক্ষেত্রে কোনও অন্তর্নিহিত ত্রুটি নেই তবে শর্ত থাকে যে চিহ্নিতকারী সর্বজনীনভাবে সত্য (সংকলন সময়ে) এবং শর্তসাপেক্ষ নয়

বেসিক পদ্ধতির তুলনায় বাস্তবে কোনও অতিরিক্ত বৈশিষ্ট্য / পদ্ধতি না থাকলেও বিভিন্ন ব্যতিক্রমগুলির মধ্যে ঠিক কীভাবে আপনার আলাদা হওয়া উচিত।

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


4
"আপনি কেবলমাত্র একটি শ্রেণী থেকে উত্তরাধিকারী হতে পারেন তবে আপনি অনেকগুলি ইন্টারফেস প্রয়োগ করতে পারেন।" যদিও প্রতিটি ভাষার ক্ষেত্রে এটি সত্য নয়। কিছু ভাষা একাধিক শ্রেণীর উত্তরাধিকারের অনুমতি দেয়।
কেনেথ কে।

কেনেথ যেমন বলেছিলেন, দুটি জনপ্রিয় ভাষায় একাধিক উত্তরাধিকার, সি ++ এবং পাইথন রয়েছে। threeআপনার ইন্টারফেসগুলি ব্যবহার না করার অসুবিধাগুলির উদাহরণের বর্গটি আসলে C ++ এ বৈধ, উদাহরণস্বরূপ, এই চারটি উদাহরণের জন্য এটি সঠিকভাবে কাজ করে। প্রকৃতপক্ষে এই সমস্তটি ভাষা হিসাবে সি # এর সীমাবদ্ধতা বলে মনে হয় বরং আপনি যখন ইন্টারফেস ব্যবহার করা উচিত তখন উত্তরাধিকার ব্যবহার না করার একটি সতর্কতামূলক কাহিনী।
আফিম

63

পলিমারফিজমটি ব্যবহার থেকে রোধ করতে আমি এটি ব্যবহার করি।

বলুন যে আপনার 15 টি পৃথক ক্লাস রয়েছে যেগুলি NamedEntityতাদের উত্তরাধিকার শৃঙ্খলে কোথাও বেস ক্লাস হিসাবে রয়েছে এবং আপনি একটি নতুন পদ্ধতি লিখছেন যা কেবলমাত্র প্রযোজ্য OrderDateInfo

আপনি "স্বাক্ষর" হিসাবে কেবল স্বাক্ষরটি লিখতে পারেন

void MyMethodThatShouldOnlyTakeOrderDateInfos(NamedEntity foo)

এবং আশা করুন এবং প্রার্থনা করবেন না যাতে কেউ সেখানে টাইপ করার জন্য টাইপ সিস্টেমটিকে অপব্যবহার করে FooBazNamedEntity

অথবা আপনি কেবল "লিখতে" পারেন void MyMethod(OrderDateInfo foo)। এখন এটি সংকলক প্রয়োগ করেছেন। সরল, মার্জিত এবং লোকে ভুল না করে তার উপর নির্ভর করে না।

এছাড়াও, @ ক্যান্ডিড_আরঞ্জ যেমন উল্লেখ করেছে , ব্যতিক্রমগুলি এটির দুর্দান্ত ঘটনা। খুব কমই (এবং আমার অর্থ খুব, খুব বিরল) আপনি কি সবসময়ই ধরতে চান catch (Exception e)? আপনার অ্যাপ্লিকেশনটির জন্য সম্ভবত আপনি একটি SqlExceptionবা একটি FileNotFoundExceptionবা একটি কাস্টম ব্যতিক্রম ধরতে চান । এই ক্লাসগুলি প্রায়শই বেস Exceptionক্লাসের চেয়ে বেশি কোনও ডেটা বা কার্যকারিতা সরবরাহ করে না তবে এগুলি আপনাকে পরীক্ষা না করে কোনও প্রকারের ক্ষেত্র পরীক্ষা করে বা নির্দিষ্ট পাঠ্যের জন্য অনুসন্ধান না করে যা উপস্থাপন করে তা আলাদা করতে দেয়।

সামগ্রিকভাবে, আপনি যদি বেস ক্লাসটি ব্যবহার করেন তবে তার চেয়ে কম সংখ্যক প্রকারের সংক্ষিপ্ততর সেট ব্যবহার করার অনুমতি দেওয়ার জন্য টাইপ সিস্টেমটি পাওয়া এটি একটি কৌশল। আমি বলতে চাইছি, আপনি আপনার সমস্ত ভেরিয়েবল এবং যুক্তিগুলি টাইপযুক্ত হিসাবে সংজ্ঞায়িত করতে পারেন Objectতবে এটি কেবল আপনার কাজকে আরও শক্ত করে তুলবে, তাই না?


4
আমার নতুনত্বকে ক্ষমা করুন তবে আমি কৌতূহল করছি কেন অর্ডারডেটইনফো সম্পত্তি হিসাবে একটি নামডেন্টিটি অবজেক্ট রাখার চেয়ে ভাল উপায় হবে না?
আদম বি

9
@ অ্যাডামবি এটি একটি বৈধ নকশা পছন্দ। এটি আরও ভাল কিনা তা নির্ভর করে এটি অন্যান্য জিনিসের মধ্যে কীসের জন্য ব্যবহৃত হবে তার উপর। ব্যতিক্রম ক্ষেত্রে, আমি ব্যতিক্রম সম্পত্তি সহ একটি নতুন শ্রেণি তৈরি করতে পারি না কারণ তখন ভাষা (আমার জন্য সি #) আমাকে এড়াতে দেয় না। অন্যান্য ডিজাইনের বিবেচনা থাকতে পারে যা উত্তরাধিকারের চেয়ে রচনা ব্যবহার না করে। অনেক সময় রচনা ভাল হয়। এটি কেবল আপনার সিস্টেমে নির্ভর করে।
বেকুজ

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

8
@ লোগার সত্য যে আমার স্তন্যপায়ী প্রাণী এবং স্তন্যপায়ী প্রাণীর মধ্যে পার্থক্য রয়েছে। তবে আমি যদি আমার অন্তঃস্থ স্তন্যপায়ী প্রাণীর প্রতি সত্যই থেকেছি তবে আপনি কখনই তারতম্যটি জানতে পারবেন না। আপনি ভাবতে পারেন যে আমি কেন এক ঝাঁকুনিতে এতগুলি বিভিন্ন ধরণের দুধ দিতে পারি।
candied_orange

5
@ অ্যাডামবি আপনি এটি করতে পারেন এবং এটি রচনা-ওভার-উত্তরাধিকার হিসাবে পরিচিত। তবে আপনি এটির NamedEntityজন্য নামকরণ করবেন, উদাহরণস্বরূপ EntityName, যাতে বর্ণিত হওয়ার সাথে রচনাটি বোধগম্য হয়।
সেবাস্তিয়ান রেডল

28

উত্তরাধিকারের এটি আমার প্রিয় ব্যবহার। আমি এটি বেশিরভাগ ব্যতিক্রমগুলির জন্য ব্যবহার করি যা আরও ভাল, আরও নির্দিষ্ট, নাম ব্যবহার করতে পারে

উত্তরাধিকারের নিয়মিত সমস্যা দীর্ঘ শৃঙ্খলার দিকে পরিচালিত করে এবং ইয়ো-ই সমস্যা তৈরি করে কারণ এখানে আপনাকে শৃঙ্খলে প্রেরণা দেওয়ার মতো কিছু নেই।


1
হুঁ, ভাল পয়েন্ট পুনরায় ব্যতিক্রম। আমি এটি করতে একটি ভয়াবহ জিনিস বলতে যাচ্ছি। তবে আপনি অন্যথায় চমৎকার ব্যবহারের ক্ষেত্রে আমাকে রাজি করেছেন।
ডেভিড আরনো

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

আমি এটা এর মূল্য ইশারা যে একটি নতুন শ্রেণী অপরের থেকে inheriting মনে করেন নতুন ক্লাসের নাম - একটি নতুন সম্পত্তি যোগ করুন। আরও ভাল নাম সহ ব্যতিক্রম তৈরি করার সময় আপনি ঠিক এটি ব্যবহার করেন।
লোগান পিকআপ

1

আইএমএইচও ক্লাস ডিজাইনটি ভুল। এটা করা উচিত.

public class EntityName
{
    public int Id { get; set; }
    public string Text { get; set; }
}

public class OrderDateInfo
{
    public EntityName Name { get; set; }
}

OrderDateInfoNameএ একটি আরও প্রাকৃতিক সম্পর্ক এবং এটি এমন দুটি ক্লাস বোঝার জন্য তৈরি করে যা মূল প্রশ্নটিকে উত্সাহিত করে না।

NamedEntityপ্যারামিটার হিসাবে গৃহীত যে কোনও পদ্ধতিতে কেবলমাত্র সম্পত্তি Idএবং Nameবৈশিষ্ট্যের প্রতি আগ্রহী হওয়া উচিত , সুতরাং EntityNameপরিবর্তে গ্রহণের জন্য এ জাতীয় কোনও পদ্ধতি পরিবর্তন করা উচিত ।

মূল নকশার জন্য আমি গ্রহণযোগ্য একমাত্র প্রযুক্তিগত কারণ হ'ল সম্পত্তি বাঁধাই, যা ওপি উল্লেখ করেছে। একটি ক্র্যাপ ফ্রেমওয়ার্ক অতিরিক্ত সম্পত্তি সঙ্গে মানিয়ে নিতে এবং আবদ্ধ করতে সক্ষম হবে না object.Name.Id। তবে যদি আপনার বাঁধার কাঠামোটি এটি মোকাবেলা করতে না পারে তবে তালিকায় যুক্ত করার জন্য আপনার আরও কিছু প্রযুক্তি debtণ রয়েছে।

আমি @ ফ্ল্যাটারের উত্তরটি সহ যাব, তবে বৈশিষ্ট্যযুক্ত প্রচুর ইন্টারফেসের সাথে আপনি প্রচুর বয়লারপ্লেট কোড লিখে শেষ করবেন, এমনকি সি # এর সুদৃশ্য স্বয়ংক্রিয় বৈশিষ্ট্যও। জাভাতে এটা করার কথা ভাবুন!


1

শ্রেণিগুলি আচরণ প্রকাশ করে এবং ডেটা স্ট্রাকচারগুলি ডেটা প্রকাশ করে।

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

একটি সাধারণ শীর্ষ স্তরের ডেটা কাঠামো কেন?

সুতরাং আপনি শীর্ষ স্তরের ডেটা টাইপ ব্যবহার করতে পারেন। বৈশিষ্ট্যগুলি সমস্ত সেখানে রয়েছে তা নিশ্চিত করে বিভিন্ন ডেটা স্ট্রাকচারের বৃহত সেটগুলিতে একটি নীতি নিশ্চিত করতে এটি টাইপ সিস্টেমের উপকারের অনুমতি দেয়।

শীর্ষ স্তরের একটিকে অন্তর্ভুক্ত করে এমন কোনও ডেটা স্ট্রাকচার কেন রয়েছে, তবে কিছুই জুড়েছে না?

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

Top level data structure - Named
   property: name;

Bottom level data structure - Person

উপরের শ্রেণিবিন্যাসে, আমরা কোনও ব্যক্তির নাম উল্লেখ করা সুবিধাজনক বলে মনে করি, যাতে লোকেরা তাদের নামটি পেতে এবং তাদের নাম পরিবর্তন করতে পারে। যদিও Personডেটা কাঠামোতে অতিরিক্ত সম্পত্তি যুক্ত করা যুক্তিসঙ্গত হতে পারে যে সমস্যার সমাধান আমরা করছি সেই ব্যক্তির একটি নিখুঁত মডেলিংয়ের প্রয়োজন হয় না, এবং তাই আমরা সাধারণ বৈশিষ্ট্যাদি ageইত্যাদি যুক্ত করতে অবহেলা করি lected

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

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