আমার কি কোনও অবজেক্ট কনস্ট্রাক্টরে পাস করা উচিত, বা ক্লাসে ইনস্ট্যান্ট করা উচিত?


10

এই দুটি উদাহরণ বিবেচনা করুন:

কোনও কনস্ট্রাক্টরের কাছে কোনও বস্তু পাস করা

class ExampleA
{
  private $config;
  public function __construct($config)
  {
     $this->config = $config;
  }
}
$config = new Config;
$exampleA = new ExampleA($config);

ক্লাস ইনস্ট্যান্ট করছে

class ExampleB
{
  private $config;
  public function __construct()
  {
     $this->config = new Config;
  }
}
$exampleA = new ExampleA();

কোনও সম্পত্তি হিসাবে সম্পত্তি যুক্ত করার সঠিক উপায় কোনটি? আমার কখন অন্যটির ওপরে ব্যবহার করা উচিত? ইউনিট টেস্টিং আমার ব্যবহার করা উচিত কি প্রভাবিত করে?



9
@ ফ্রেস্ট্রেটেড উইথফোর্ডস ডিজাইনার - এটি কোড পর্যালোচনার জন্য উপযুক্ত নয়।
ক্রিসএফ

উত্তর:


14

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

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


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

3
@ অ্যাডউডকক এটি ইউনিট পরীক্ষার তুলনায় অন্যান্য পরিস্থিতিতে সত্যই নয়। বস্তুর হয় হয় বাইরে থেকে নির্ভরতা প্রয়োজন হয় বা এটি এটি অভ্যন্তরে পরিচালনা করে। উভয় / হয় না।
ম্যাটডেভে

9

টেস্টিবিলিটি সম্পর্কে ভুলবেন না!

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

সুতরাং আমি প্রথম বিকল্প সঙ্গে যেতে হবে ExampleA


আমি কেন পরীক্ষার উল্লেখ করেছি - এটি যুক্ত করার জন্য ধন্যবাদ :)
বন্দী

5

নির্ভরতার আজীবন পরিচালনার জন্য যদি বিষয়টির দায়বদ্ধতা থাকে , তবে কনস্ট্রাক্টারে অবজেক্টটি তৈরি করা ঠিক আছে (এবং এটি ডেস্ট্রাক্টরে নিষ্পত্তি করুন) * *

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

এই ক্ষেত্রে আমি মনে করি না যে আপনার ক্লাসের কনফিগারেশন তৈরির জন্য দায়িত্ব নেওয়া উচিত, যদি না এটি ডিসপোজ করার জন্যও দায়বদ্ধ থাকে বা ক্লাসএর প্রতিটি উদাহরণের জন্য যদি কনফিগারটি অনন্য থাকে।

* পরীক্ষার ক্ষেত্রে সহায়তা করার জন্য, নির্মাতা তার নির্মাণকারীর উপর নির্ভরতা তৈরির জন্য কারখানার শ্রেণি / পদ্ধতির একটি রেফারেন্স নিতে পারেন, সংহতকরণ এবং পরীক্ষার ক্ষমতা বৃদ্ধি করে।

//Object which manages the lifetime of its dependency (C#):
public class ClassA : IDisposable
{
    public Config Config { get; private set; }

    public ClassA()
    {
        this.Config = new Config(); // Tightly coupled to Config class...
    }

    public void Dispose()
    {
        this.Config.Dispose();
    }
}

// Object which does not manage its dependency:
public class ClassA
{
    public Config Config { get; set; }

    public ClassA(Config config) // dependency may be injected...
    {
        this.Config = config;
    }
}

// Object which manages its dependency in a testable way:
public class ClassA : IDisposable
{
    public Config Config { get; private set; }

    public ClassA(IConfigFactory configFactory) // dependency may be mocked...
    {
        this.Config = configFactory.BuildConfig();
    }

    public void Dispose()
    {
        this.Config.Dispose();
    }
}

2

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

আপনার উদাহরণে, যদি আপনার কনফিগার ক্লাসটি থাকে:

ক) অপ্রয়োজনীয় বরাদ্দ রয়েছে যেমন পুল বা কারখানা পদ্ধতি থেকে আসা।

খ) বরাদ্দ ব্যর্থ হতে পারে। নির্মাতাকে এটিকে পাসে পরিষ্কার করা এ সমস্যাটি এড়িয়ে চলে।

গ) আসলে কনফিগারেশনের একটি সাবক্লাস।

অবজেক্টটি কনস্ট্রাক্টরে পাস করা সর্বাধিক নমনীয়তা দেয়।


1

নীচের উত্তরটি ভুল, তবে আমি এটি অন্যদের থেকে শিখতে রাখব (নীচে দেখুন)

ইন ExampleA, আপনি Configএকাধিক ক্লাস জুড়ে একই উদাহরণ ব্যবহার করতে পারেন । তবে, যদি Configপুরো অ্যাপ্লিকেশনটির মধ্যে কেবল একটি উদাহরণ Configথাকতে পারে তবে একাধিক উদাহরণ না এড়াতে সিঙ্গলটন প্যাটার্নটি প্রয়োগ করার বিষয়টি বিবেচনা করুন Config। এবং যদি Configএকটি সিঙ্গলটন হয় তবে আপনি পরিবর্তে নিম্নলিখিতটি করতে পারেন:

class ExampleA
{
  private $config;
  public function __construct()
  {
     $this->config = Config->getInstance();
  }
}
$exampleA = new ExampleA();

ইন ExampleB, অপরপক্ষে, আপনি সবসময় একটি পৃথক উদাহরণস্বরূপ পাবেন Configপ্রতিটি নিদর্শনের জন্য ExampleB

আপনার কোন সংস্করণটি প্রয়োগ করা উচিত তা নির্ভর করে অ্যাপ্লিকেশন কীভাবে উদাহরণগুলি পরিচালনা করবে Config:

  • যদি প্রতিটি ঘটনার ExampleXপৃথক উদাহরণ থাকতে Configপারে তবে সাথে যান ExampleB;
  • প্রতিটি উদাহরণ যদি ExampleXএকটি (এবং শুধুমাত্র একটি) উদাহরণ ভাগ করে নিবে Config, ব্যবহার করুন ExampleA with Config Singleton;
  • উদাহরণস্বরূপ যদি ExampleXবিভিন্ন দৃষ্টান্ত ব্যবহার করা যায় তবে এটি Configআটকে দিন ExampleA

কেন সিঙ্গলটনে রূপান্তর Configকরা ভুল:

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

  1. যদি ExampleAনিজস্ব রেফারেন্স আহরণ Configউদাহরণস্বরূপ, ক্লাস শক্তভাবে মিলিত করা হবে না। (কিছু সাবক্লাস বলুন) ExampleAএর আলাদা সংস্করণ ব্যবহার করার কোনও উদাহরণ থাকবে না Config। এটি যদি ExampleAকোনও মক-আপ উদাহরণ ব্যবহার করে পরীক্ষা করতে চান তবে Configএটি সরবরাহ করার কোনও উপায় নেই বলেই এটি ভয়াবহ ExampleA

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

  3. যদিও এক এবং একমাত্র এক উদাহরণ Configসমস্ত চিরন্তন সত্য হতে পারে, এমনটি ঘটতে পারে যে আপনি কয়েকটি সাবক্লাস ব্যবহার করতে সক্ষম হতে চান Config(এখনও কেবলমাত্র একটি উদাহরণ রয়েছে)। কিন্তু, যেহেতু কোড সরাসরি মাধ্যমে উদাহরণস্বরূপ পায় getInstance()এর Configএকটি যা, staticপদ্ধতি, সেখানে উপশ্রেণী পেতে কোনও উপায় নেই। আবার কোড অবশ্যই নতুন করে লিখতে হবে।

  4. কমপক্ষে কেবলমাত্র এপিআইটি দেখার সময় যে ExampleAব্যবহারগুলি ব্যবহার Configকরা হয় তা গোপন করা হবে ExampleA। এটি খারাপ জিনিস হতে পারে বা নাও হতে পারে তবে ব্যক্তিগতভাবে আমি অনুভব করি যে এটি একটি অসুবিধার মতো বোধ করে; উদাহরণস্বরূপ, রক্ষণাবেক্ষণের সময়, Configঅন্যান্য ক্লাসের প্রয়োগের দিকে নজর না দিয়ে কোন ক্লাসগুলি পরিবর্তনের দ্বারা প্রভাবিত হবে তা সন্ধানের সহজ উপায় নেই ।

  5. এমনকি যদি সিঙ্গলটনExampleA ব্যবহার করে তবে এটি নিজের মধ্যে সমস্যা না হলেও এটি এখনও পরীক্ষার দৃষ্টিকোণ থেকে সমস্যা হয়ে উঠতে পারে। সিঙ্গেলটন অবজেক্টগুলি রাষ্ট্র বহন করবে যা অ্যাপ্লিকেশন শেষ হওয়া অবধি স্থায়ী থাকবে। ইউনিট পরীক্ষা চলাকালীন এটি একটি সমস্যা হতে পারে কারণ আপনি চান যে একটি পরীক্ষা অন্যের থেকে পৃথক হয়ে যায় (যেমন একটি পরীক্ষা চালানো অন্যের ফলাফলকে প্রভাবিত করে না)। এটি ঠিক করার জন্য, প্রতিটি পরীক্ষার রান (সম্ভাব্যভাবে পুরো অ্যাপ্লিকেশনটি পুনরায় চালু করতে হবে) এর মধ্যে সিঙ্গেলটন অবজেক্টটি ধ্বংস করতে হবে, যা সময় সাপেক্ষ হতে পারে (ক্লান্তিকর এবং বিরক্তিকরতার কথা উল্লেখ না করা)। Config

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


4
আমি এটি করার সুপারিশ করব না .. এইভাবে আপনি দৃ couple়ভাবে দম্পতি ক্লাস ExampleAএবং Config- যা ভাল জিনিস নয়।
পল

@ পল: এটি সত্য। ভাল ধরা, সে সম্পর্কে ভাবেনি।
গ্যাবলিন

3
পরীক্ষার যোগ্যতার কারণে আমি সর্বদা সিঙ্গলেটন ব্যবহারের বিরুদ্ধে সুপারিশ করব। এগুলি মূলত গ্লোবাল ভেরিয়েবল এবং নির্ভরতা উপহাস করা অসম্ভব।
ম্যাটডেভে

4
আপনার ভুল করার কারণে আমি সিলেটলেটগুলি ব্যবহার করার পরামর্শ দিয়েছি recommend
রায়নস

1

করতে সবচেয়ে সহজ জিনিস দম্পতি হয় ExampleAথেকে Config। আপনার আরও সহজ জিনিসটি করা উচিত, যদি না আরও জটিল কিছু করার জন্য বাধ্যতামূলক কারণ না থাকে।

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


1

আপনার প্রথম উদাহরণটি নির্ভরতা ইঞ্জেকশন প্যাটার্নের একটি উদাহরণ। বাহ্যিক নির্ভরতা সহ একটি শ্রেণি নির্মাতা, সেটার ইত্যাদি দ্বারা নির্ভরতা হস্তান্তর করা হয়

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

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

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


0

যদি আপনার ক্লাসটি $configবাইরের ক্লাসগুলিতে প্রকাশ না করে তবে আমি এটি নির্মাণকারীর ভিতরে তৈরি করব। এইভাবে, আপনি আপনার অভ্যন্তরীণ রাষ্ট্র ব্যক্তিগত রাখছেন।

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


0

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

উদাহরণ বি দৃ strongly়ভাবে কংক্রিট শ্রেণীর কনফিগারেশনে মিলিত হয়েছে যা খারাপ

কোনও বস্তুকে ইনস্ট্যান্ট করা ক্লাসগুলির মধ্যে একটি শক্তিশালী মিলন তৈরি করে। এটি একটি কারখানার শ্রেণিতে করা উচিত।

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