উত্তরাধিকার এবং নির্ভরতা ইনজেকশন


101

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

সরলীকৃত উদাহরণ:

export class AbstractComponent {
  constructor(private myservice: MyService) {
    // Inject the service I need for all components
  }
}

export MyComponent extends AbstractComponent {
  constructor(private anotherService: AnotherService) {
    super(); // This gives an error as super constructor needs an argument
  }
}

আমি MyServiceপ্রতিটি এবং প্রতিটি উপাদান মধ্যে ইনজেকশনের মাধ্যমে এটি সমাধান করতে এবং super()কলটি জন্য এই যুক্তি ব্যবহার করতে পারেন কিন্তু এটি অবশ্যই একরকম অবাস্তব।

কীভাবে আমার উপাদানগুলি সঠিকভাবে সংগঠিত করবেন যাতে তারা সুপার বর্গ থেকে কোনও পরিষেবাদি উত্তরাধিকার সূত্রে আসে?


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

আপনার উত্তর (আপনার প্রশ্নের ইনলাইন) আমার কাছে তা বোঝায় না। এইভাবে আপনি এমন একটি ইনজেক্টর তৈরি করেন যা আপনার অ্যাপ্লিকেশনের জন্য কৌনিক ব্যবহারকারী ইঞ্জেক্টারের থেকে পৃথক। new MyService()ইনজেকশনের পরিবর্তে ব্যবহার করা আপনাকে ঠিক একই ফলাফল দেয় (আরও দক্ষ ছাড়া)। আপনি যদি একই পরিষেবা উদাহরণটি বিভিন্ন পরিষেবা এবং / অথবা উপাদানগুলিতে ভাগ করতে চান তবে এটি কাজ করবে না। প্রতিটি শ্রেণি অন্য MyServiceউদাহরণ পাবে।
গন্টার জ্যাচবাউয়ার

আপনি সম্পূর্ণরূপে ঠিক বলেছেন, আমার কোডটি প্রচুর উদাহরণ তৈরি করবে myService। এমন একটি সমাধান খুঁজে
পেয়েছে

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

উত্তর:


73

আমি প্রতিটি এবং প্রতিটি উপাদানগুলির মধ্যে মাই সার্ভিসেস ইনজেকশনের মাধ্যমে এটি সমাধান করতে পারি এবং সুপার () কলের জন্য সেই যুক্তিটি ব্যবহার করতে পারি তবে এটি অবশ্যই একরকম অবাস্তব।

এটা অযৌক্তিক নয়। কনস্ট্রাক্টর এবং কনস্ট্রাক্টর ইঞ্জেকশন এভাবে কাজ করে।

প্রতিটি ইনজেকশনযোগ্য ক্লাসকে কনস্ট্রাক্টর প্যারামিটার হিসাবে নির্ভরতাগুলি ঘোষণা করতে হয় এবং সুপারক্লাসেও যদি নির্ভরতা থাকে তবে এগুলি সাবক্লাসের কনস্ট্রাক্টরে তালিকাভুক্ত করা উচিত এবং super(dep1, dep2)কল সহ সুপারক্লাসের পাশ দিয়ে যেতে হবে।

একটি ইনজেক্টর কাছাকাছি পাস এবং জরুরীভাবে নির্ভরতা অর্জনের গুরুতর অসুবিধা রয়েছে।

এটি নির্ভরশীলতাগুলি গোপন করে যা কোডটি পড়া শক্ত করে।
এটি Angular2 ডিআই কীভাবে কাজ করে তার সাথে পরিচিত একজনের প্রত্যাশা লঙ্ঘন করে।
এটি অফলাইন সংকলনটি ভেঙে দেয় যা কার্যকারিতা উন্নত করতে এবং কোডের আকার হ্রাস করতে ঘোষিত এবং আবশ্যক ডিআই প্রতিস্থাপনের জন্য স্ট্যাটিক কোড উত্পন্ন করে।


6
কেবল এটি পরিষ্কার করার জন্য: আমার এটি সর্বদাই প্রয়োজন। সেই নির্ভরতাটিকে আমার সুপার ক্লাসের দিকে নিয়ে যাওয়ার চেষ্টা করছেন যাতে প্রতিটি উত্পন্ন ক্লাসটি প্রতিটি উত্পন্ন ক্লাসে স্বতন্ত্রভাবে ইনজেক্ট করার প্রয়োজন ছাড়াই পরিষেবাটি অ্যাক্সেস করতে পারে।
ম্যাক্সবিবি

9
তার নিজের প্রশ্নের উত্তর একটি কুৎসিত হ্যাক। এটি ইতিমধ্যে কীভাবে করা উচিত তা প্রশ্নটি ইতিমধ্যে প্রদর্শন করে। আমি আরও কিছু বিশদ ব্যাখ্যা।
গন্টার জ্যাচবাউর

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

6
আমি ওপি'র "হ্যাক" এর মাধ্যমে এই উত্তরটি সত্যই ব্যবহার করতে (এবং চালিয়ে যেতে) চাই। তবে আমাকে বলতে হবে এটি ডিআরওয়াই থেকে অনেক দূরে বলে মনে হচ্ছে এবং যখন আমি বেস ক্লাসে নির্ভরতা যুক্ত করতে চাই তখন খুব বেদনাদায়ক হয়। আমাকে superপ্রায় 20+ ক্লাসে সিটার ইঞ্জেকশনগুলি (এবং সম্পর্কিত কলগুলি) যুক্ত করতে হয়েছিল এবং এই সংখ্যাটি কেবল ভবিষ্যতে বাড়তে চলেছে। সুতরাং দুটি জিনিস: 1) আমি "বৃহত কোডবেস" এটি করতে দেখে ঘৃণা করব; এবং 2) qVim এবং vscode এর জন্য Thank ctrl+.

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

66

আপডেট সমাধান, বৈশ্বিক ইনজেক্টর ব্যবহার করে তৈরি হওয়া মাই সার্ভিসির একাধিক ঘটনা প্রতিরোধ করে।

import {Injector} from '@angular/core';
import {MyServiceA} from './myServiceA';
import {MyServiceB} from './myServiceB';
import {MyServiceC} from './myServiceC';

export class AbstractComponent {
  protected myServiceA:MyServiceA;
  protected myServiceB:MyServiceB;
  protected myServiceC:MyServiceC;

  constructor(injector: Injector) {
    this.settingsServiceA = injector.get(MyServiceA);
    this.settingsServiceB = injector.get(MyServiceB);
    this.settingsServiceB = injector.get(MyServiceC);
  }
}

export MyComponent extends AbstractComponent {
  constructor(
    private anotherService: AnotherService,
    injector: Injector
  ) {
    super(injector);

    this.myServiceA.JustCallSomeMethod();
    this.myServiceB.JustCallAnotherMethod();
    this.myServiceC.JustOneMoreMethod();
  }
}

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

এই সমাধানটির জন্য কয়েকটি কনস রয়েছে (আমার মূল প্রশ্নের নীচে @ গন্তার জ্যাচবাউরের কাছ থেকে মন্তব্য দেখুন):

  • বৈশ্বিক ইনজেক্টর ইনজেকশন কেবল তখনই উন্নতি হয় যখন বিভিন্ন স্থানে বিভিন্ন জায়গায় ইঞ্জেকশন লাগানো দরকার। আপনার যদি কেবল একটি ভাগ করা পরিষেবা থাকে তবে উত্পন্ন শ্রেণীর মধ্যে সেই পরিষেবাটি ইনজেক্ট করা সম্ভবত আরও ভাল / সহজ (
  • আমার সমাধান এবং তার প্রস্তাবিত বিকল্পের উভয়ই অসুবিধা হ'ল যেটি কোন শ্রেণিতে কোন পরিষেবা নির্ভর করে তা দেখতে এটি আরও কঠিন করে তোলে।

অ্যাঙ্গুলার 2 এ নির্ভরতা ইনজেকশন সম্পর্কে খুব লিখিতভাবে ব্যাখ্যা করার জন্য এই ব্লগ পোস্টটি দেখুন যা সমস্যার সমাধান করতে আমাকে ব্যাপকভাবে সহায়তা করেছে: http://blog.thoughtram.io/angular/2015/05/18/d dependency-inication-in-angular- 2.html


7
এটি আসলে কী পরিষেবাগুলি প্রকৃতপক্ষে ইনজেক্ট করা হয়েছে তা বোঝা বেশ কঠিন করে তোলে।
সাইমন ডুফর

4
এটা this.myServiceA = injector.get(MyServiceA);ইত্যাদি হওয়া উচিত নয় ?
জেনসন-বাটন-ইভেন্ট

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

4
একই পরিষেবাটির একাধিক উদাহরণের ঝুঁকি নেই। অ্যাপ্লিকেশনটির বিভিন্ন শাখায় ঘটতে পারে এমন একাধিক ঘটনা প্রতিরোধ করতে আপনাকে কেবল আপনার অ্যাপ্লিকেশনটির মূলে একটি পরিষেবা সরবরাহ করতে হবে। উত্তরাধিকারের পরিবর্তনের পরিষেবাগুলি পাস করা ক্লাসগুলির নতুন উদাহরণ তৈরি করে না । @ গুনটার জোচবাউরের উত্তর সঠিক।
ktamlyn

@ ম্যাক্সএইচবি আপনি কি Injectorকোনও পরামিতি শৃঙ্খলাবদ্ধ না হওয়ার জন্য বিশ্বব্যাপী প্রসারিত এক্সপ্লোর পরিচালনা করেছেন AbstractComponent? তবে, আমি মনে করি যে অগোছালো কনস্ট্রাক্টর শৃঙ্খলা এড়ানোর জন্য বিস্তৃত ব্যবহৃত বেস ক্লাসে সম্পত্তি ইনজেকশন নির্ভরতা সাধারণ নিয়মের পুরোপুরি বৈধ ব্যতিক্রম।
কোয়ান্টিন-স্টারিন

5

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

উত্পন্ন শ্রেণি:

@Component({
    ...
    providers: [ProviderService]
})
export class DerivedComponent extends BaseComponent {
    constructor(protected providerService: ProviderService) {
        super(providerService);
    }
}

বেস শ্রেণি:

export class BaseComponent {
    constructor(protected providerService: ProviderService) {
        // do something with providerService
    }
}

পরিষেবা সরবরাহকারী শ্রেণি:

@Injectable()
export class ProviderService {
    constructor(private _apiService: ApiService, private _authService: AuthService) {
    }
}

4
এখানে সমস্যা হ'ল আপনি "জাঙ্ক ড্রয়ার" পরিষেবা তৈরির ঝুঁকি নিয়েছেন যা মূলত ইনজেক্টর পরিষেবার জন্য কেবলমাত্র একটি প্রক্সি।
কেপআপ

1

নির্ভরযোগ্যতা হিসাবে অন্যান্য সমস্ত পরিষেবা রয়েছে এমন একটি পরিষেবা ইনজেকশনের পরিবর্তে:

class ProviderService {
    constructor(private service1: Service1, private service2: Service2) {}
}

class BaseComponent {
    constructor(protected providerService: ProviderService) {}

    ngOnInit() {
        // Access to all application services with providerService
        this.providerService.service1
    }
}

class DerivedComponent extends BaseComponent {
    ngOnInit() {
        // Access to all application services with providerService
        this.providerService.service1
    }
}

আমি এই অতিরিক্ত পদক্ষেপটি এড়িয়ে যাব এবং বেসকম্পোন্টে সমস্ত পরিষেবা কেবল ইনজেকশন যুক্ত করব:

class BaseComponent {
    constructor(protected service1: Service1, protected service2: Service2) {}
}

class DerivedComponent extends BaseComponent {
    ngOnInit() {
        this.service1;
        this.service2;
    }
}

এই কৌশলটি 2 টি জিনিস ধরে নিয়েছে:

  1. আপনার উদ্বেগ সম্পূর্ণরূপে উপাদান উত্তরাধিকার সম্পর্কিত। সম্ভবত, আপনি এই প্রশ্নটিতে অবতারণার কারণটি হ'ল প্রচুর পরিমাণে অ শুকনো (ডাব্লুইইটি?) কোডের জন্য আপনাকে প্রতিটি উত্পন্ন শ্রেণিতে পুনরাবৃত্তি করতে হবে। আপনি যদি আপনার সমস্ত উপাদান এবং পরিষেবাদির জন্য একটি একক প্রবেশ পয়েন্টের সুবিধা পেতে চান তবে আপনাকে অতিরিক্ত পদক্ষেপটি করতে হবে।

  2. প্রতিটি উপাদান প্রসারিত BaseComponent

আপনি যদি একটি উদ্ভূত শ্রেণীর নির্মাতা ব্যবহার করার সিদ্ধান্ত নেন তবে একটি অসুবিধাও রয়েছে, কারণ আপনাকে super()সমস্ত নির্ভরতাগুলিতে কল করতে এবং পাস করতে হবে । যদিও আমি সত্যিই এমন ব্যবহারের ক্ষেত্রে দেখতে পাই না যা তার constructorপরিবর্তে ব্যবহারের প্রয়োজন হয় ngOnInitতবে এটি সম্পূর্ণরূপে সম্ভব যে এই ধরনের ব্যবহারের কেস বিদ্যমান।


4
বেস ক্লাসটি তার সন্তানের যে কোনও প্রয়োজন তার সমস্ত পরিষেবার উপর নির্ভরতা রাখে। চাইল্ড কম্পোনেন্টের সার্ভিসএ দরকার? আচ্ছা, এখন চাইল্ডকম্পোনমেন্টবিও সার্ভিসএ পেয়েছে।
knallfrosch

1

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


0

যদি প্যারেন্ট ক্লাসটি তৃতীয় পক্ষের প্লাগ-ইন থেকে পাওয়া যায় (এবং আপনি উত্সটি পরিবর্তন করতে পারবেন না) আপনি এটি করতে পারেন:

import { Injector } from '@angular/core';

export MyComponent extends AbstractComponent {
  constructor(
    protected injector: Injector,
    private anotherService: AnotherService
  ) {
    super(injector.get(MyService));
  }
}

বা সর্বাধিক ভাল উপায় (কনস্ট্রাক্টরে কেবলমাত্র একটি পরামিতি থাকুন):

import { Injector } from '@angular/core';

export MyComponent extends AbstractComponent {
  private anotherService: AnotherService;

  constructor(
    protected injector: Injector
  ) {
    super(injector.get(MyService));
    this.anotherService = injector.get(AnotherService);
  }
}

0

কৌতুক হ্যাক

কিছু সময় আগে আমার ক্লায়েন্টের কয়েকজন গতকাল দুটি বিগ কৌণিক প্রকল্পে যোগ দিতে চায় (কৌণিক v4 কৌণিক v8 তে)। প্রকল্প ভি 4 প্রতিটি উপাদানগুলির জন্য বেসভিউ ক্লাস ব্যবহার করে এবং এতে tr(key)অনুবাদগুলির জন্য পদ্ধতি রয়েছে ( ভি 8 তে আমি এনজি-ট্রান্সলেট ব্যবহার করি)। সুতরাং অনুবাদ সিস্টেম স্যুইচিং এড়াতে এবং শত শত টেম্পলেটগুলি সম্পাদনা করতে (ভি 4 তে) অথবা সমান্তরালভাবে 2 অনুবাদ সিস্টেম সেটআপ করুন আমি নিম্নলিখিত কুরুচিপূর্ণ হ্যাক ব্যবহার করি (এতে আমি গর্বিত নই) - AppModuleক্লাসে আমি নিম্নরূপ নির্মাণকারী যুক্ত করব:

export class AppModule { 
    constructor(private injector: Injector) {
        window['UglyHackInjector'] = this.injector;
    }
}

এবং এখন AbstractComponentআপনি ব্যবহার করতে পারেন

export class AbstractComponent {
  private myservice: MyService = null;

  constructor() {
    this.myservice = window['UglyHackInjector'].get(MyService);
  }
}

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