ডিআই কনটেইনারের মাধ্যমে তৈরি করা অবজেক্টের সূচনা করার জন্য কি কোনও প্যাটার্ন রয়েছে?


147

আমি আমার অবজেক্টগুলির তৈরি পরিচালনা করতে ityক্য পাওয়ার চেষ্টা করছি এবং আমি কিছু সূচনা পরামিতি রাখতে চাই যা রান-টাইম পর্যন্ত জানা যায় না:

এই মুহুর্তে আমি কীভাবে এটি করার উপায়টি ভাবতে পারি তা হ'ল ইন্টারফেসে একটি ইনিস পদ্ধতি থাকা।

interface IMyIntf {
  void Initialize(string runTimeParam);
  string RunTimeParam { get; }
}

তারপরে এটি ব্যবহার করতে (ityক্যে) আমি এটি করব:

var IMyIntf = unityContainer.Resolve<IMyIntf>();
IMyIntf.Initialize("somevalue");

এই runTimeParamদৃশ্যে প্যারাম ব্যবহারকারীর ইনপুটের ভিত্তিতে রান-টাইমে নির্ধারিত হয়। এখানে তুচ্ছ ঘটনা কেবল এর মান দেয় runTimeParamতবে বাস্তবে প্যারামিটারটি ফাইলের নামের মতো হবে এবং পদ্ধতিটি ফাইলের সাথে কিছু করবে initial

এটি বেশ কয়েকটি সমস্যা তৈরি করে, যথা Initializeপদ্ধতিটি ইন্টারফেসে উপলব্ধ এবং একাধিকবার বলা যেতে পারে। বাস্তবায়নে একটি পতাকা সেট করা এবং বারবার কল করতে ব্যতিক্রম ছুঁড়ে ফেলা Initializeমনে হচ্ছে এটিকে জটিল un

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

সম্পাদনা: ইন্টারফেসটি আরও কিছুটা বর্ণনা করেছেন।


9
আপনি একটি ডিআই কনটেইনার ব্যবহারের বিন্দুটি অনুপস্থিত। নির্ভরতাগুলি আপনার জন্য সমাধান হওয়ার কথা।
পিয়ারটেন

আপনি কোথা থেকে আপনার প্রয়োজনীয় পরামিতিগুলি পাচ্ছেন? (কনফিগারেশন ফাইল, ডিবি, ??)
জাইমে

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

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

আমি বলতে চাইছি আপনার অ্যাপে 100 টি ক্লাস রয়েছে যার উপর এই পদ্ধতির প্রয়োগ করা যেতে পারে; তারপরে আপনাকে আপনার ক্লাসের জন্য অতিরিক্ত 100 টি কারখানার ক্লাস + 100 ইন্টারফেস তৈরি করতে হবে এবং আপনি যদি প্রাথমিকভাবে () পদ্ধতিটি ব্যবহার করে থাকেন তবে আপনি পালিয়ে যেতে পারেন।
হালকা

উত্তর:


276

যে কোনও জায়গা যেখানে আপনার একটি নির্দিষ্ট নির্ভরতা তৈরির জন্য রান-টাইম মান প্রয়োজন, অ্যাবস্ট্রাক্ট ফ্যাক্টরিই এর সমাধান।

ইন্টারফেসে পদ্ধতিগুলি ইনিশিয়াল করার ফলে একটি ফাঁসী বিমূর্তির গন্ধ হয় ।

আপনার ক্ষেত্রে আমি বলব যে আপনার IMyIntfইন্টারফেসটি কীভাবে এটি ব্যবহার করতে হবে তা আপনার মডেল করা উচিত - আপনি কীভাবে এটির বাস্তবায়ন তৈরি করতে চান তা নয়। এটি একটি বাস্তবায়ন বিশদ।

সুতরাং, ইন্টারফেসটি সহজভাবে হওয়া উচিত:

public interface IMyIntf
{
    string RunTimeParam { get; }
}

অ্যাবস্ট্রাক্ট কারখানার সংজ্ঞা দিন:

public interface IMyIntfFactory
{
    IMyIntf Create(string runTimeParam);
}

আপনি এখন একটি কংক্রিট বাস্তবায়ন তৈরি করতে পারেন IMyIntfFactoryযা এর IMyIntfমতো কংক্রিটের উদাহরণ তৈরি করে :

public class MyIntf : IMyIntf
{
    private readonly string runTimeParam;

    public MyIntf(string runTimeParam)
    {
        if(runTimeParam == null)
        {
            throw new ArgumentNullException("runTimeParam");
        }

        this.runTimeParam = runTimeParam;
    }

    public string RunTimeParam
    {
        get { return this.runTimeParam; }
    }
}

লক্ষ্য করুন কীভাবে এটি কীওয়ার্ড ব্যবহার করে আমাদের শ্রেণীর আক্রমণকারীদের রক্ষা করতে সহায়তা করে readonly। দুর্গন্ধযুক্ত কোনও প্রাথমিক পদ্ধতি প্রয়োজনীয় নয়।

একটি IMyIntfFactoryবাস্তবায়ন এই হিসাবে সহজ হতে পারে:

public class MyIntfFactory : IMyIntfFactory
{
    public IMyIntf Create(string runTimeParam)
    {
        return new MyIntf(runTimeParam);
    }
}

আপনার সমস্ত গ্রাহক যেখানে আপনার একটি IMyIntfউদাহরণ প্রয়োজন , আপনি কেবল কনস্ট্রাক্টর ইনজেকশনেরIMyIntfFactory মাধ্যমে এটির অনুরোধ করে নির্ভরতা নেবেন ।

IMyIntfFactoryআপনি যদি এটির সঠিকভাবে নিবন্ধন করেন তবে এর জন্য কোনও ডিআই কনটেইনার এর লবণের মূল্য আপনার জন্য অ্যান্ট-ওয়্যার করতে সক্ষম হবে ।


13
সমস্যাটি হ'ল কোনও পদ্ধতি (যেমন ইনিশিয়ালাইজ করা) আপনার এপিআই-র অংশ, যদিও কনস্ট্রাক্টর নয়। blog.ploeh.dk/2011/02/28/InterfacesAreAccessModifiers.aspx
মার্ক

13
তদ্ব্যতীত, একটি প্রাথমিক পদ্ধতিটি অস্থায়ী সংযোগকে
মার্ক

2
@ ডারলিন আপনি আমার বইয়ের ৮.৩. section অনুচ্ছেদে বর্ণিত একটি অলস সূচনাযুক্ত ডেকরেটার ব্যবহার করতে সক্ষম হতে পারেন । আমি আমার উপস্থাপনা বিগ অবজেক্ট গ্রাফস আপ ফ্রন্টে অনুরূপ কিছু উদাহরণ প্রদান করি ।
মার্ক সিম্যান

2
@ মার্ক যদি কারখানাটির MyIntfবাস্তবায়নটি তৈরির জন্য runTimeParam(পড়ুন: অন্যান্য পরিষেবাদিগুলি যেগুলি একটি আইওসি দ্বারা সমাধান করতে চায়) এর চেয়ে বেশি প্রয়োজন হয়, তবে আপনি এখনও আপনার কারখানার সেই নির্ভরতাগুলি সমাধান করার মুখোমুখি হচ্ছেন। এটি সমাধানের জন্য কারখানার নির্মাতাদের মধ্যে সেই নির্ভরতাগুলি প্রেরণের @ ফিল্ডস্যান্ডলারের উত্তরটি আমি পছন্দ করি - এটি কি আপনারও গ্রহণ করা উচিত?
জেফ

2
দুর্দান্ত জিনিস, তবে এই অন্যান্য প্রশ্নের উত্তর আপনার উত্তরটি আমার কাছে পৌঁছেছে।
জেফ

15

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

আপনার যদি কনস্ট্রাক্টরে একটি প্রসঙ্গ-নির্দিষ্ট পরামিতিটি প্রয়োজন হয়, একটি বিকল্প হ'ল একটি কারখানা তৈরি করা যা আপনার পরিষেবা নির্ভরতাগুলি কনস্ট্রাক্টরের মাধ্যমে সমাধান করে এবং আপনার রান-টাইম প্যারামিটারটিকে তৈরি () পদ্ধতির পরামিতি হিসাবে নেয় (বা জেনারেট করে ( ), বিল্ড () বা আপনি নিজের কারখানার পদ্ধতিগুলির নাম দিন)।

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


5

আমি এমন পরিবেশে কয়েকবার এসে পৌঁছেছি যেখানে আমি গতিশীলভাবে মডেল অবজেক্টগুলির উপর ভিত্তি করে ভিউমোডেল অবজেক্ট তৈরি করছি (এই অন্যান্য স্ট্যাকওভারফ্লো পোস্টটি দ্বারা সত্যই বর্ণিত )।

আমি পছন্দ করেছি কীভাবে নিনজেক্ট এক্সটেনশন যা আপনাকে গতিশীলভাবে ইন্টারফেসের উপর ভিত্তি করে কারখানা তৈরি করতে দেয়:

Bind<IMyFactory>().ToFactory();

আমি কোনো অনুরূপ কার্যকারিতা সরাসরি খুঁজে পাইনি ইউনিটি ; সুতরাং আমি IUnityContainer এ আমার নিজস্ব এক্সটেনশন লিখেছি যা আপনাকে এমন ফ্যাক্টরিগুলি নিবন্ধভুক্ত করতে দেয় যা বিদ্যমান অবজেক্টগুলি থেকে ডেটা ভিত্তিক নতুন অবজেক্ট তৈরি করবে যা মূলত এক ধরণের শ্রেণিবদ্ধ থেকে অন্য ধরণের শ্রেণিবিন্যাসে ম্যাপিং: ইউনিটিম্যাপিংফ্যাক্টরি @ গিটহাব

সরলতা এবং পঠনযোগ্যতার একটি লক্ষ্য নিয়ে আমি একটি এক্সটেনশান দিয়ে শেষ করেছি যা আপনাকে পৃথক কারখানার ক্লাস বা ইন্টারফেস (একটি বাস্তব সময়ের সঞ্চয়কারী) না ঘোষণা করে সরাসরি ম্যাপিংগুলি নির্দিষ্ট করতে দেয়। আপনি ঠিক সেখানে ম্যাপিংস যুক্ত করুন যেখানে আপনি সাধারণ বুটস্ট্র্যাপিং প্রক্রিয়া চলাকালীন ক্লাসগুলি নিবন্ধভুক্ত করেন ...

//make sure to register the output...
container.RegisterType<IImageWidgetViewModel, ImageWidgetViewModel>();
container.RegisterType<ITextWidgetViewModel, TextWidgetViewModel>();

//define the mapping between different class hierarchies...
container.RegisterFactory<IWidget, IWidgetViewModel>()
.AddMap<IImageWidget, IImageWidgetViewModel>()
.AddMap<ITextWidget, ITextWidgetViewModel>();

তারপরে আপনি কেবল সিআই এর জন্য কনস্ট্রাক্টরে ম্যাপিং কারখানার ইন্টারফেসটি ঘোষণা করুন এবং এর তৈরি () পদ্ধতিটি ব্যবহার করুন ...

public ImageWidgetViewModel(IImageWidget widget, IAnotherDependency d) { }

public TextWidgetViewModel(ITextWidget widget) { }

public ContainerViewModel(object data, IFactory<IWidget, IWidgetViewModel> factory)
{
    IList<IWidgetViewModel> children = new List<IWidgetViewModel>();
    foreach (IWidget w in data.Widgets)
        children.Add(factory.Create(w));
}

একটি অতিরিক্ত বোনাস হিসাবে, ম্যাপযুক্ত শ্রেণীর নির্মাতাদের কোনও অতিরিক্ত নির্ভরতা অবজেক্ট তৈরির সময়ও সমাধান হয়ে যাবে।

স্পষ্টতই, এটি প্রতিটি সমস্যার সমাধান করবে না তবে এটি এখন পর্যন্ত আমাকে বেশ ভালভাবে পরিবেশন করেছে তাই আমি ভেবেছিলাম আমার এটি ভাগ করে নেওয়া উচিত। গিটহাবে প্রকল্পের সাইটে আরও ডকুমেন্টেশন রয়েছে।


1

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

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

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

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


তার জন্য ধন্যবাদ. আমি আসলে ডিআই ফ্রেমওয়ার্কগুলি মূল্যায়ন করছি এবং এনআইজেক্টটি আমার পরেরটি হতে চলেছে।
ইগর জেভাাকা

@ জোহান: সরবরাহকারী? github.com/ninject/ninject/wiki/...
এন্থনি

1

আমি মনে করি আমি এটি সমাধান করেছি এবং এটি সুস্বাস্থ্য বোধ করে, তাই এটি অবশ্যই অর্ধেক ঠিক হবে :))

আমি IMyIntfএকটি "গিটার" এবং একটি "সেটার" ইন্টারফেসে বিভক্ত হয়েছি । তাই:

interface IMyIntf {
  string RunTimeParam { get; }
}


interface IMyIntfSetter {
  void Initialize(string runTimeParam);
  IMyIntf MyIntf {get; }
}

তারপরে বাস্তবায়ন:

class MyIntfImpl : IMyIntf, IMyIntfSetter {
  string _runTimeParam;

  void Initialize(string runTimeParam) {
    _runTimeParam = runTimeParam;
  }

  string RunTimeParam { get; }

  IMyIntf MyIntf {get {return this;} }
}

//Unity configuration:
//Only the setter is mapped to the implementation.
container.RegisterType<IMyIntfSetter, MyIntfImpl>();
//To retrieve an instance of IMyIntf:
//1. create the setter
IMyIntfSetter setter = container.Resolve<IMyIntfSetter>();
//2. Init it
setter.Initialize("someparam");
//3. Use the IMyIntf accessor
IMyIntf intf = setter.MyIntf;

IMyIntfSetter.Initialize()এখনও একাধিকবার বলা যেতে পারে তবে সার্ভিস লোকেটার দৃষ্টান্তের বিটগুলি ব্যবহার করে আমরা এটিকে বেশ সুন্দরভাবে গুটিয়ে রাখতে পারি যাতে এটি IMyIntfSetterপ্রায় অভ্যন্তরীণ ইন্টারফেস থেকে আলাদা IMyIntf


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