কীওয়ার্ড ব্যবহার করে কীভাবে DRY নীতি প্রয়োগ করবেন?


23

এই পদ্ধতিগুলি বিবেচনা করুন:

public List<Employee> GetAllEmployees()
{
    using (Entities entities = new Entities())
    {
        return entities.Employees.ToList();
    }
}

public List<Job> GetAllJobs()
{
    using (Entities entities = new Entities())
    {
        return entities.Jobs.ToList();
    }
}

public List<Task> GetAllTasksOfTheJob(Job job)
{
    using (Entities entities = new Entities())
    {
        return entities.Tasks.Where(t => t.JobId == job.Id).ToList();
    }
}

ব্লক ব্যবহার করা একই এবং এখানে 3 বার পুনরাবৃত্তি হয়েছে (অবশ্যই, বাস্তব প্রয়োগে 100 বারেরও বেশি)) usingব্লকের জন্য কীভাবে ডিআরওয়াই (নিজেকে পুনরাবৃত্তি করবেন না) প্রিন্সিপাল বাস্তবায়ন সম্ভব ? এটিকে কি আদৌ ডিআরওয়াই অধ্যক্ষের লঙ্ঘন হিসাবে বিবেচনা করা হয়?

আপডেট: আমি usingব্লকের অভ্যন্তরে কী বাস্তবায়ন হয়েছে সে সম্পর্কে কথা বলছি না । আমি এখানে যা বলতে চাইছি তা হ'ল using (Entities entities = new Entities())। এই লাইনটি 100 বার বা তারও বেশি বার পুনরাবৃত্তি করা হয়।


2
এই সি # হয়? আপনার প্রশ্নের উত্তরটি ভাষা নির্ভর হতে পারে
ডেভিড

হ্যাঁ, ডেভিড, দুঃখিত যে আমি আমার ভাষার উল্লেখ করি নি। এটি উত্তরকে কীভাবে প্রভাবিত করতে পারে?
সা Saeedদ নেমতি

কিছু ভাষায় নির্দিষ্ট বাক্য গঠন থাকতে পারে যা আপনাকে আপনার কোডের কিছুটা ফ্যাক্টর করতে সহায়তা করতে পারে। আমি সি # জানি না, তবে রুবিতে, আমি মনে করি আপনি ব্যবহারের অংশটি নির্ধারণ করতে ব্লক ব্যবহার করতে পারেন।
ডেভিড

স্টেটমেন্ট ব্যবহার আসলে সাহায্যের এড়ানোর পুনরাবৃত্তিমূলক কোডিং সঙ্গে রিসোর্স নিষ্পত্তি পরিচালনার সময় শুষ্ক নীতি প্রয়োগ করতে C # এর ভাষা সমর্থন প্রদান করে সৎকার নকশা প্যাটার্ন । এর অর্থ এই নয় যে আমরা জিনিসগুলি DRYer করার উপায় খুঁজে পাচ্ছি না! ব্যক্তিগতভাবে, আমি ডিআরওয়াইকে একটি পুনরাবৃত্ত প্রক্রিয়া হিসাবে মনে করি।
জন টোবলার

উত্তর:


24

একটি ধারণা এটি গ্রহণ করবে একটি ফাংশন সঙ্গে এটি মোড়ানো Func

এটার মতো কিছু

public K UsingT<T,K>(Func<T,K> f) where T:IDisposable,new()
{
    using (T t = new T())
    {
        return f(t);
    }
}

তারপরে আপনার উপরের কোডটি হয়ে যায়

public List<Employee> GetAllEmployees()
{
    return UsingT<Entities,List<Employee>>(e=>e.Employees.ToList());
}

public List<Job> GetAllJobs()
{
    return UsingT<Entities,List<Job>>(e=>e.Jobs.ToList());
}

public List<Task> GetAllTasksOfTheJob(Job job)
{
    return UsingT<Entities,List<Task>>(e=>e.Tasks.Where(t => t.JobId == job.Id).ToList());
}

আমিও Entitiesএকটি টাইপ পরম তৈরি করেছি , কারণ আমি ধরে নিচ্ছি যে আপনি একাধিক প্রকারের সাথে এটি করছেন। যদি আপনি না হন তবে আপনি এটি সরিয়ে ফেলতে পারেন এবং কেবল রিটার্ন টাইপের জন্য প্যারাম টাইপ ব্যবহার করতে পারেন।

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

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

//forget the Entities type param
public T UsingEntities<T>(Func<Entities,T> f)
{
    using (Entities e = new Entities())
    {
        return f(e);
    }
}
//forget the Entities type param, and return an IList
public IList<T> ListFromEntities<T>(Func<Entities,IEnumerable<T>> f)
{
    using (Entities e = new Entities())
    {
        return f(e).ToList();
    }
}
//doing the .ToList() forces the results to enumerate before `e` gets disposed.

1
+1 সুন্দর সমাধান, যদিও এটি আসল সমস্যাটি (মূল প্রশ্নের সাথে অন্তর্ভুক্ত নয়), অর্থাৎ এর বহু সংখ্যার সমাধান করে না Entities
back2dos

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

+1 আমি মনে করি এই পদ্ধতিটি ভাল। এবং পাঠযোগ্যতা উন্নত করা যেতে পারে। উদাহরণস্বরূপ, এর মধ্যে "ToList" রাখুন WithEntities, তার Func<T,IEnumerable<K>>পরিবর্তে ব্যবহার করুন Func<T,K>এবং "WithEntities" কে আরও ভাল নাম দিন (যেমন নির্বাচন করুন)। এবং আমি মনে করি না "সত্তা" এখানে জেনেরিক পরামিতি হওয়া দরকার।
ডক ব্রাউন

1
এই কাজ করার জন্য, সীমাবদ্ধতা হতে হবে where T : IDisposable, new(), যেমন usingপ্রয়োজন IDisposableকাজ করার জন্য।
অ্যান্টনি পেগ্রাম

1
@ অ্যান্টনি পেগ্রাম: স্থির, ধন্যবাদ! (ব্রাউজার উইন্ডোতে সি # কোডিংয়ের জন্য এটিই আমি পেয়েছি)
ব্রুক 13

23

আমার কাছে এটি একাধিকবার একই সংগ্রহের উপর ভবিষ্যদ্বাণী-ইং সম্পর্কে উদ্বেগ করার মতো হবে: এটি আপনার কিছু করা দরকার। এটি আরও বিমূর্ত করার কোনও প্রচেষ্টা কোডটি খুব কম পাঠযোগ্য করে তুলবে।


দুর্দান্ত উপমা @ বেন +1
সা Saeedদ নেমতি

3
আমি রাজি নই, দুঃখিত। লেনদেনের সুযোগ সম্পর্কে ওপির মন্তব্যগুলি পড়ুন এবং আপনি যখন এই জাতীয় কোডটি 500 বার লিখেছেন তখন আপনাকে কী করতে হবে তা ভেবে দেখুন এবং তারপরে লক্ষ্য করুন যে আপনাকে একই জিনিসটি 500 বার পরিবর্তন করতে হবে। এই জাতীয় কোডটি পুনরাবৃত্তি করা ঠিক আছে তবেই যদি আপনার <10 টি ফাংশন থাকে।
ডক ব্রাউন

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

1
আমার কাছে দেখে মনে হচ্ছে আপনি অনলাইনারে তিনটি লাইনার তৈরি করছেন ... আপনি এখনও নিজেকে পুনরাবৃত্তি করছেন।
জিম ওল্ফ

এটি প্রসঙ্গ নির্ভর, যদি foreachখুব বড় সংগ্রহ শেষ হয় বা foreachলুপের মধ্যে যুক্তি সময়সাপেক্ষ হয়। একটি নীতিবাক্য আমি গ্রহণ করতে এসেছি: অবহেলা করবেন না তবে সর্বদা আপনার পদ্ধতির প্রতি সচেতন থাকুন
Coops

9

দেখে মনে হচ্ছে আপনি DRY নীতিটি দিয়ে "একবার এবং কেবল একবার" নীতিটি বিভ্রান্ত করছেন। DRY নীতিতে বলা হয়েছে:

প্রতিটি জ্ঞানের অংশ অবশ্যই সিস্টেমের মধ্যে একক, দ্ব্যর্থহীন, অনুমোদনমূলক প্রতিনিধিত্ব করতে হবে।

তবে ওয়ান ও ওলি ওয়ান নীতি কিছুটা আলাদা।

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

ডিআরওয়াই নীতিটি সাধারণত বাস্তব যুক্তির প্রসঙ্গে ব্যবহৃত হয়, বিবৃতিগুলি ব্যবহার করে এত বেশি বাড়াবাড়ি হয় না:

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

সূত্র


7

আমি usingএখানে ব্যবহার দেখতে ব্যর্থ :

কেমন:

public List<Employee> GetAllEmployees() {
    return (new Entities()).Employees.ToList();
}
public List<Job> GetAllJobs() {
    return (new Entities()).Jobs.ToList();
}
public List<Task> GetAllTasksOfTheJob(Job job) {
    return (new Entities()).Tasks.Where(t => t.JobId == job.Id).ToList();
}

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

private Entities entities = new Entities();//not sure C# allows for that kind of initialization, but you can do it in the constructor if needed

public List<Employee> GetAllEmployees() {
    return entities.Employees.ToList();
}
public List<Job> GetAllJobs() {
    return entities.Jobs.ToList();
}
public List<Task> GetAllTasksOfTheJob(Job job) {
    return entities.Tasks.Where(t => t.JobId == job.Id).ToList();
}

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

সম্পাদনা:
ঠিক আছে সুতরাং সমস্যাটি আসলে ব্যবহারের বিবৃতি নয়, সমস্যাটি আপনি প্রতিবার তৈরি করা অবজেক্টের উপর নির্ভরতা। আমি কোনও কনস্ট্রাক্টর ইনজেকশন দেওয়ার পরামর্শ দেব:

private delegate Entities query();//this should be injected from the outside (upon construction for example)
public List<Employee> GetAllEmployees() {
    using (var entities = query()) {//AFAIK C# can infer the type here
        return entities.Employees.ToList();
    }
}
//... and so on

2
তবে @ ব্যাক 2 ডস, অনেকগুলি স্থান রয়েছে যেখানে আমরা using (CustomTransaction transaction = new CustomTransaction())আমাদের লেনদেনের এএ লেনদেনের সুযোগটি নির্ধারণ করতে কোড ব্লক ব্যবহার করি । এটি একটি একক অবজেক্টে বান্ডিল হতে পারে না এবং যে কোনও জায়গায় আপনি লেনদেন ব্যবহার করতে চান, আপনার একটি ব্লক লেখা উচিত। এখন কি তোমার কাছ থেকে যে লেনদেনের ধরণ পরিবর্তন করতে চান তাহলে CustomTransactionকরতে BuiltInTransaction500 জনেরও বেশী পদ্ধতিতে? এটি আমার কাছে পুনরাবৃত্তি করা কাজ এবং DRY অধ্যক্ষের লঙ্ঘনের উদাহরণ বলে মনে হয়।
সা Saeedদ নেমতি

3
এখানে "ব্যবহার" করা ডেটা প্রসঙ্গটি বন্ধ করে দেয় তাই এই পদ্ধতির বাইরে অলস লোডিং সম্ভব নয়।
স্টিভেন স্ট্রিগা

@ সাeedদ: আপনি যখন নির্ভরতা ইনজেকশনটি সন্ধান করেন তখন তা। তবে প্রশ্নটিতে বর্ণিত মামলা থেকে এটি বেশ আলাদা বলে মনে হচ্ছে।
সিভিএন

@ সাeedদ: পোস্ট আপডেট হয়েছে।
back2dos

@ উইকএন্ডওয়ারিওর using(এই প্রসঙ্গে) এখনও কি আরও একটি অজানা "সুবিধাজনক সিনট্যাক্স"? এটি ব্যবহার করতে কেন এত চমৎকার =)
কপস

4

ডুপ্লিকেট কোডটি ব্যবহার না করেই (এটি ডুপ্লিকেট কোড এবং আসলে একটি চেষ্টা এর সাথে তুলনা করে atch আমি আপনার কোডটি এভাবে রিফেক্টর করব:

 public List<T> GetAll(Func<Entities, IEnumerable<T>> getter) {
    using (Entities entities = new Entities())
    {
        return getter().ToList();
    }
 }

public List<Employee> GetAllEmployees()
{
    return GetAll(e => e.Employees);
}

public List<Job> GetAllJobs()
{
    return GetAll(e => e.Jobs);
}

public List<Task> GetAllTasksOfTheJob(Job job)
{
    return GetAll(e => e.Tasks.Where(t => t.JobId == job.Id));
}

3

যেহেতু এখানে সর্বশেষ ব্যতীত কোনও ধরণের ব্যবসায়ের যুক্তি নেই। আমার দৃষ্টিতে এটি সত্যিই শুকনো নয়।

ইউজিং ব্লকে শেষেরটিতে কোনও ডিআরওয়াই নেই তবে আমি অনুমান করি যেখানে যেখানে ক্লজটি ব্যবহৃত হয়েছে সেখানে পরিবর্তন হওয়া উচিত।

কোড জেনারেটরের জন্য এটি একটি সাধারণ কাজ। কোড জেনারেটর লিখুন এবং কভার করুন এবং এটি প্রতিটি ধরণের জন্য উত্পন্ন করতে দিন।


না @ আরুনমুর এখানে একটি ভুল বোঝাবুঝি হয়েছিল। ডিআরওয়াই দ্বারা, আমি using (Entities entities = new Entities())ব্লক বোঝাতে চাইছি । মানে, কোডের এই লাইনটি 100 বার পুনরাবৃত্তি হয়েছে এবং আরও এবং আরও বার বার পুনরাবৃত্তি হচ্ছে।
সা Saeedদ নেমতি

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

1
@arnumur - ব্যবহার সর্বদা বিরতি করা খুব সহজ নয়। আমার প্রায়শই ভাল যুক্তি থাকে যা ডেটা প্রসঙ্গে কোন বিকল্পগুলি ব্যবহার করতে হবে তা নির্ধারণ করে। এটি খুব সম্ভব যে ভুল সংযোগের স্ট্রিংটি পাস হতে পারে
মরগান হের্লোকার

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

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

2

যেহেতু আপনি একই ডিসপোজেবল অবজেক্টটিকে বারবার তৈরি এবং ধ্বংস করছেন, তাই আপনার ক্লাস নিজেই আইডিস্পোজযোগ্য প্যাটার্নটি প্রয়োগের জন্য ভাল প্রার্থী।

class ThisClass : IDisposable
{
    protected virtual Entities Context { get; set; }

    protected virtual void Dispose( bool disposing )
    {
        if ( disposing && Context != null )
            Context.Dispose();
    }

    public void Dispose()
    {
        Dispose( true );
    }

    public ThisClass()
    {
        Context = new Entities();
    }

    public List<Employee> GetAllEmployees()
    {
        return Context.Employees.ToList();
    }

    public List<Job> GetAllJobs()
    {
        return Context.Jobs.ToList();
    }

    public List<Task> GetAllTasksOfTheJob(Job job)
    {
        return Context.Tasks.Where(t => t.JobId == job.Id).ToList();
    }
}

এটি আপনার শ্রেণীর উদাহরণ তৈরি করার সময় আপনার কেবল "ব্যবহার" দরকার " আপনি যদি না চান যে শ্রেণিগুলি বিষয়গুলি নিষ্পত্তি করার জন্য দায়বদ্ধ হয় তবে আপনি পদ্ধতিগুলি নির্ভরতাটিকে আর্গুমেন্ট হিসাবে গ্রহণ করতে পারেন:

public static List<Employee> GetAllEmployees( Entities entities )
{
    return entities.Employees.ToList();
}

public static List<Job> GetAllJobs( Entities entities )
{
    return entities.Jobs.ToList();
}

public static List<Task> GetAllTasksOfTheJob( Entities entities, Job job )
{
    return entities.Tasks.Where(t => t.JobId == job.Id).ToList();
}

1

আমার প্রিয় বিট অবিস্মরণীয় যাদু!

public class Blah
{
  IEnumerable<T> Wrap(Func<Entities, IEnumerable<T>> act)
  {
    using(var entities = new Entities()) { return act(entities); }
  }

  public List<Employee> GetAllEmployees()
  {
    return Wrap(e => e.Employees.ToList());
  }

  public List<Job> GetAllJobs()
  {
    return Wrap(e => e.Jobs.ToList());
  }

  public List<Task> GetAllTasksOfTheJob(Job job)
  {
    return Wrap(e => e.Tasks.Where(x ....).ToList());
  }
}

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


ফানক <আইনিম্যুয়াল <টি>, সত্ত্বা> এর জন্য আপনার টাইপ পরামিতিগুলি ভুল ক্রমে রয়েছে। (আমার উত্তরটি দেখুন যা মূলত একই জিনিসটি রয়েছে)
ব্রুক 17

ঠিক আছে, সংশোধন করার পক্ষে যথেষ্ট সহজ। সঠিক অর্ডার কী তা আমার কখনও মনে নেই। আমার Funcউচিত যথেষ্ট পরিমাণে আমার ব্যবহার করা উচিত।
ট্র্যাভিস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.