নির্ভরতা ইনজেকশনের জন্য পাইথোনিক উপায় কী?


84

ভূমিকা

জাভা-র জন্য, নির্ভরতা ইনজেকশন খাঁটি ওওপি হিসাবে কাজ করে, অর্থাত্ আপনি কার্যকর করার জন্য একটি ইন্টারফেস সরবরাহ করেন এবং আপনার ফ্রেমওয়ার্ক কোডে সংজ্ঞায়িত ইন্টারফেস প্রয়োগ করে এমন একটি শ্রেণীর উদাহরণ গ্রহণ করুন।

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

ব্যবহারের ক্ষেত্রে

বলুন এটি ফ্রেমওয়ার্ক কোড:

class FrameworkClass():
    def __init__(self, ...):
        ...

    def do_the_job(self, ...):
        # some stuff
        # depending on some external function

বেসিক অ্যাপ্রোচ

সর্বাধিক নিখুঁত (এবং সম্ভবত সেরা?) উপায়টি হল বাহ্যিক ফাংশনটি FrameworkClassকন্সট্রাক্টরের কাছে সরবরাহ করা প্রয়োজন এবং তারপরে do_the_jobপদ্ধতিটি থেকে আহ্বান করা উচিত ।

ফ্রেমওয়ার্ক কোড:

class FrameworkClass():
    def __init__(self, func):
        self.func = func

    def do_the_job(self, ...):
        # some stuff
        self.func(...)

ক্লায়েন্ট কোড:

def my_func():
    # my implementation

framework_instance = FrameworkClass(my_func)
framework_instance.do_the_job(...)

প্রশ্ন

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

আপডেট: কংক্রিট পরিস্থিতি

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

স্পষ্টতই, ফ্রেমওয়ার্কটি ব্যবহারকারী বা অন্য কোনও অ্যাপ্লিকেশন নির্দিষ্ট যুক্তি সম্পর্কিত কিছুই জানে না, তাই প্রমাণীকরণের কাজটি করার জন্য ক্লায়েন্ট কোডটি অবশ্যই গ্রাহক কার্যকারিতাটিকে ফ্রেমওয়ার্কে ইনজেকশন করতে পারে।


4
আপনি কেন "প্রয়োগ করার জন্য একটি ইন্টারফেস সরবরাহ করেন না এবং আপনার কাঠামো কোডে সংজ্ঞায়িত ইন্টারফেস প্রয়োগ করে এমন শ্রেণীর উদাহরণ গ্রহণ করে না" ? পাইথন আপনি একটি ইন এই কাজ করতে হবে EAFP শৈলী (অর্থাত এটা যে ইন্টারফেস পূরণ করে এবং একটি অনুমান AttributeErrorবা TypeError, কিন্তু অন্যথায় এটা একই অন্যথায় উত্থাপিত পরার)।
jonrsharpe

এটি ব্যবহার করে কাজ করা সহজ absএর ABCMetaসঙ্গে ক্লাসের অধীনে একটি ক্লাস @abstractmethodপ্রসাধক, এবং কোন ম্যানুয়াল বৈধতা। কেবল কয়েকটি বিকল্প এবং পরামর্শ পেতে চাই। আপনি যেটাকে উদ্ধৃত করেছেন সেটি হ'ল সবচেয়ে পরিষ্কার, তবে আমি মনে করি আরও ওভারহেড দিয়ে।
বাগরাত

তাহলে আমি জানি না আপনি কোন প্রশ্ন জিজ্ঞাসা করার চেষ্টা করছেন।
jonrsharpe

ঠিক আছে, আমি অন্য কথায় চেষ্টা করব। সমস্যাটি পরিষ্কার is পাইথোনিক উপায়ে এটি কীভাবে করা যায় প্রশ্ন। বিকল্প 1 : আপনি যেভাবে উদ্ধৃত করেছেন, বিকল্প 2 : আমি প্রশ্নটিতে বর্ণিত প্রাথমিক পদ্ধতির । সুতরাং প্রশ্নটি হল, এটি করার জন্য অন্য কোনও পাইথোনিক উপায় আছে?
বাগরাত

উত্তর:


66

রায়মন্ড হেট্টিংগার দেখুন - সুপার সুপার সুপার! - পাইকন 2015 ডিআই-র পরিবর্তে কীভাবে সুপার এবং একাধিক উত্তরাধিকার ব্যবহার করা যায় সে সম্পর্কে একটি যুক্তির জন্য । আপনার কাছে পুরো ভিডিওটি দেখার সময় না থাকলে 15 মিনিটে লাফিয়ে যান (তবে আমি এটি সমস্ত দেখার পরামর্শ দিই)।

এই ভিডিওতে বর্ণিত যা প্রয়োগ করা যায় তার উদাহরণ এখানে আপনার উদাহরণে দেওয়া হল:

ফ্রেমওয়ার্ক কোড:

class TokenInterface():
    def getUserFromToken(self, token):
        raise NotImplementedError

class FrameworkClass(TokenInterface):
    def do_the_job(self, ...):
        # some stuff
        self.user = super().getUserFromToken(...)

ক্লায়েন্ট কোড:

class SQLUserFromToken(TokenInterface):
    def getUserFromToken(self, token):      
        # load the user from the database
        return user

class ClientFrameworkClass(FrameworkClass, SQLUserFromToken):
    pass

framework_instance = ClientFrameworkClass()
framework_instance.do_the_job(...)

এটি কাজ করবে কারণ পাইথন এমআরও গ্যারান্টি দিবে যে getUserFromToken ক্লায়েন্ট পদ্ধতিটি (যদি সুপার () ব্যবহার করা হয়) বলে। আপনি পাইথন ২.x এ থাকলে কোডটি পরিবর্তন করতে হবে।

এখানে আরও একটি সুবিধা হ'ল ক্লায়েন্ট যদি কোনও বাস্তবায়ন সরবরাহ না করে তবে এটি একটি ব্যতিক্রম বাড়াবে।

অবশ্যই, এটি আসলে নির্ভরতা ইনজেকশন নয়, এটি একাধিক উত্তরাধিকার এবং মিশ্রণ, তবে এটি আপনার সমস্যা সমাধানের এক অজগর উপায়।


10
এই উত্তরটি বিবেচনা করা হয়েছে super():)
বাগরাত

4
রেইমন্ড এটিকে সিআই বলেছিলেন, আমি ভেবেছিলাম যে এটি একটি খাঁটি মিশ্রণ। তবে এটি কি পাইথনে মিক্সিন এবং সিআই কার্যত একরকম হতে পারে? পার্থক্যটি কেবলমাত্র ইঙ্গিতের স্তর। মিক্সিন একটি শ্রেণির স্তরে নির্ভরতা ইনজেকশনের সময় সিআই একটি উদাহরণের মধ্যে নির্ভরতা ইনজেকশনে ফেলে।
nad2000

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

6
যদিও আমি এটি খুব মার্জিত মনে করি, এই পদ্ধতির সাথে আমার দুটি সমস্যা রয়েছে: ১. যখন আপনার ক্লাসে সার্টারাল আইটেমগুলি ইনজেকশনের প্রয়োজন হয় তখন কী ঘটে? 2. উত্তরাধিকার বেশিরভাগ ক্ষেত্রে "একটি হয়" / বিশেষীকরণ-বোধে ব্যবহৃত হয়। ডিআই এর জন্য এটি ব্যবহার করা সেই ধারণাটিকে অস্বীকার করে (উদাহরণস্বরূপ যদি আমি কোনও উপস্থাপকের মধ্যে কোনও পরিষেবা ইনজেক্ট করতে চাই))
আলজস্টো

18

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

আপনার উদাহরণ অনুসরণ করে এটি কিছু অনুরূপ হতে পারে:

# framework.py
class FrameworkClass():
    def __init__(self, func):
        self.func = func

    def do_the_job(self):
        # some stuff
        self.func()

আপনার কাস্টম ফাংশন:

# my_stuff.py
def my_func():
    print('aww yiss')

অ্যাপ্লিকেশনটিতে কোথাও আপনি একটি বুটস্ট্র্যাপ ফাইল তৈরি করতে চান যা সমস্ত সংজ্ঞায়িত নির্ভরতার উপর নজর রাখে:

# bootstrap.py
import inject
from .my_stuff import my_func

def configure_injection(binder):
    binder.bind(FrameworkClass, FrameworkClass(my_func))

inject.configure(configure_injection)

এবং তারপরে আপনি এইভাবে কোডটি গ্রাস করতে পারেন:

# some_module.py (has to be loaded with bootstrap.py already loaded somewhere in your app)
import inject
from .framework import FrameworkClass

framework_instance = inject.instance(FrameworkClass)
framework_instance.do_the_job()

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

সুতরাং আপনার প্রশ্নের সরাসরি উত্তর দেওয়া খুব কঠিন হবে। আমার মনে হয় আসল প্রশ্নটি হল: পাইথনের ডিআই-র জন্য কি কিছু দেশীয় সমর্থন রয়েছে? এবং উত্তরটি হ'ল দুঃখের বিষয়: না।


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

'ইনজেকশন' লাইব্রেরিতে লিঙ্কটির জন্য ধন্যবাদ। আমি ডিআই-র যে শূন্যস্থান পূরণ করতে চেয়েছি তা পূরণ করার জন্য আমি এ পর্যন্ত সবচেয়ে কাছাকাছি খুঁজে পেয়েছি - এবং বোনাস, এটি আসলে বজায় রাখা হচ্ছে!
অ্যান্ডি মর্টিমার

14

কিছু সময় আগে আমি পাইথনিক - নির্ভরতা ইনজেক্টর তৈরির জন্য একটি উচ্চাকাঙ্ক্ষা সহ নির্ভরতা ইনজেকশন মাইক্রোফ্রেমওয়ার্ক লিখেছিলাম । আপনার কোডটি ব্যবহারের ক্ষেত্রে এটির মতো দেখতে কেমন:

"""Example of dependency injection in Python."""

import logging
import sqlite3

import boto.s3.connection

import example.main
import example.services

import dependency_injector.containers as containers
import dependency_injector.providers as providers


class Platform(containers.DeclarativeContainer):
    """IoC container of platform service providers."""

    logger = providers.Singleton(logging.Logger, name='example')

    database = providers.Singleton(sqlite3.connect, ':memory:')

    s3 = providers.Singleton(boto.s3.connection.S3Connection,
                             aws_access_key_id='KEY',
                             aws_secret_access_key='SECRET')


class Services(containers.DeclarativeContainer):
    """IoC container of business service providers."""

    users = providers.Factory(example.services.UsersService,
                              logger=Platform.logger,
                              db=Platform.database)

    auth = providers.Factory(example.services.AuthService,
                             logger=Platform.logger,
                             db=Platform.database,
                             token_ttl=3600)

    photos = providers.Factory(example.services.PhotosService,
                               logger=Platform.logger,
                               db=Platform.database,
                               s3=Platform.s3)


class Application(containers.DeclarativeContainer):
    """IoC container of application component providers."""

    main = providers.Callable(example.main.main,
                              users_service=Services.users,
                              auth_service=Services.auth,
                              photos_service=Services.photos)

এখানে এই উদাহরণটির আরও বিস্তৃত বিবরণের লিঙ্ক এখানে দেওয়া হয়েছে - http://python - d dependency-injector.ets-labs.org/example/services_miniapp.html

আশা করি এটি কিছুটা সাহায্য করতে পারে। আরো তথ্যের জন্য অনুগ্রহ করে পরিদর্শন করুন:


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

4
হাই @ বিলডরোজ আমার উত্তরটি এসও মন্তব্য হওয়ার জন্য অনেক দীর্ঘ হিসাবে বিবেচিত হলেও, আমি একটি গিথুব ইস্যু তৈরি করেছি এবং আমার উত্তরটি সেখানে পোস্ট করেছি - github.com/ets-labs/python-d dependency - injector / issues / 197 :) আশা করি এটি সহায়তা করে, ধন্যবাদ, রোমান
রোমান মোগিলাতভ

3

নির্ভরতা ইনজেকশন একটি সাধারণ কৌশল যা পাইথন সরাসরি সমর্থন করে। কোন অতিরিক্ত গ্রন্থাগার প্রয়োজন হয়। প্রকারের ইঙ্গিতগুলি ব্যবহার করা স্পষ্টতা এবং পাঠযোগ্যতার উন্নতি করতে পারে।

ফ্রেমওয়ার্ক কোড:

class UserStore():
    """
    The base class for accessing a user's information.
    The client must extend this class and implement its methods.
    """
    def get_name(self, token):
        raise NotImplementedError

class WebFramework():
    def __init__(self, user_store: UserStore):
        self.user_store = user_store

    def greet_user(self, token):
        user_name = self.user_store.get_name(token)
        print(f'Good day to you, {user_name}!')

ক্লায়েন্ট কোড:

class AlwaysMaryUser(UserStore):
    def get_name(self, token):      
        return 'Mary'

class SQLUserStore(UserStore):
    def __init__(self, db_params):
        self.db_params = db_params

    def get_name(self, token):
        # TODO: Implement the database lookup
        raise NotImplementedError

client = WebFramework(AlwaysMaryUser())
client.greet_user('user_token')

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


2

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

প্রকৃতপক্ষে আপনি মেটাক্লাস এবং শ্রেণি সজ্জা ব্যবহার করে <100 লাইনে একটি বেসিক ডিআই কাঠামো প্রয়োগ করতে পারেন ।

কম আক্রমণাত্মক সমাধানের জন্য, এই নির্মাণগুলি জেনেরিক কাঠামোর মধ্যে কাস্টম প্রয়োগগুলি প্লাগ-ইন করতে ব্যবহৃত হতে পারে।


2

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

এখানে একটি উদাহরণ

>>> class OuterClass(object):
...     def __init__(self, inner_class):
...         self.inner_class = inner_class
...
>>> class InnerClass(object):
...     def __init__(self):
...         self.forty_two = 42
...
>>> obj_graph = pinject.new_object_graph()
>>> outer_class = obj_graph.provide(OuterClass)
>>> print outer_class.inner_class.forty_two
42

এবং এখানে উত্স কোড


1

নির্ভরতা ইনজেকশন করার একটি খুব সহজ এবং পাইথোনিক উপায় হ'ল আমদানি।

আপনি একটি ছোট ইউটিলিটি ফাংশন সংজ্ঞায়িত করতে পারেন

def inject_method_from_module(modulename, methodname):
    """
    injects dynamically a method in a module
    """
    mod = importlib.import_module(modulename)
    return getattr(mod, methodname, None)

এবং তারপরে আপনি এটি ব্যবহার করতে পারেন:

myfunction = inject_method_from_module("mypackage.mymodule", "myfunction")
myfunction("a")

মাইপ্যাকেজ / mymodule.py এ আপনি মাইফ্যাঙ্কশনটি সংজ্ঞায়িত করেন

def myfunction(s):
    print("myfunction in mypackage.mymodule called with parameter:", s)

আপনি অবশ্যই ক্লাস মাইক্লাস আইসো ব্যবহার করতে পারেন। ফাংশন myfunction। আপনি যদি একটি সেটিংস.পাই ফাইলে পদ্ধতি নামের মানগুলি সংজ্ঞায়িত করেন তবে আপনি সেটিংস ফাইলের মানের উপর নির্ভর করে পদ্ধতি নামের বিভিন্ন সংস্করণ লোড করতে পারেন। জাজানো তার ডেটাবেস সংযোগ সংজ্ঞায়িত করতে এই জাতীয় স্কিম ব্যবহার করছে।


1

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

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

সুতরাং আমার সমাধানটি হ'ল:

# Framework internal
def MetaIoC(name, bases, namespace):
    cls = type("IoC{}".format(name), tuple(), namespace)
    return type(name, bases + (cls,), {})


# Entities level                                        
class Entity:
    def _lower_level_meth(self):
        raise NotImplementedError

    @property
    def entity_prop(self):
        return super(Entity, self)._lower_level_meth()


# Adapters level
class ImplementedEntity(Entity, metaclass=MetaIoC):          
    __private = 'private attribute value'                    

    def __init__(self, pub_attr):                            
        self.pub_attr = pub_attr                             

    def _lower_level_meth(self):                             
        print('{}\n{}'.format(self.pub_attr, self.__private))


# Infrastructure level                                       
if __name__ == '__main__':                                   
    ENTITY = ImplementedEntity('public attribute value')     
    ENTITY.entity_prop         

সম্পাদনা:

প্যাটার্নটি সম্পর্কে সতর্কতা অবলম্বন করুন। আমি এটি একটি বাস্তব প্রকল্পে ব্যবহার করেছি এবং এটি এটিকে নিজের মতো করে দেখায় না good প্যাটার্নটির সাথে আমার অভিজ্ঞতা সম্পর্কে মিডিয়ামে আমার পোস্ট।


অবশ্যই আইওসি এবং ডিআই সাধারণত ব্যবহৃত হয়, যা সাধারণত ব্যবহৃত হয় না তা হ'ল ডিআই ফ্রেমওয়ার্কগুলি আরও ভাল বা আরও খারাপ।
juanpa.arrivillaga

1

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

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

from simple_injection import ServiceCollection


class Dependency:
    def hello(self):
        print("Hello from Dependency!")

class Service:
    def __init__(self, dependency: Dependency):
        self._dependency = dependency

    def hello(self):
        self._dependency.hello()

collection = ServiceCollection()
collection.add_transient(Dependency)
collection.add_transient(Service)

collection.resolve(Service).hello()
# Outputs: Hello from Dependency!

এই লাইব্রেরি পরিষেবাগুলির জীবনকাল এবং বাস্তবায়নের জন্য বাধ্যতামূলক পরিষেবাগুলিকে সহায়তা করে।

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

আশাকরি এটা সাহায্য করবে. আরও তথ্যের জন্য, দয়া করে দেখুন

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