ওওপি অ্যাপ্লিকেশনটিতে প্যারামিটার পরিচালনা


15

আমি ওওপি নীতিগুলি অনুশীলনের উপায় হিসাবে সি ++ তে মাঝারি আকারের ওওপি অ্যাপ্লিকেশন লিখছি।

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

তাই আমি একটি ক্লাস তৈরি করেছি ConfigBlock। এই শ্রেণিটি সমস্ত প্যারামিটার উত্স পড়ে এবং এটি একটি উপযুক্ত ডেটা স্ট্রাকচারে সঞ্চয় করে। উদাহরণগুলি হ'ল পাথ- এবং ফাইলের নামগুলি যা কনফিগার ফাইলে অথবা --verbose CLI পতাকা ব্যবহার করে ব্যবহারকারী পরিবর্তিত হতে পারে। তারপরে, ConfigBlock.GetVerboseLevel()এই নির্দিষ্ট পরামিতিটি পড়ার জন্য কেউ কল করতে পারেন ।

আমার প্রশ্ন: একটি ক্লাসে এই জাতীয় সমস্ত রানটাইম কনফিগার ডেটা সংগ্রহ করা কি ভাল অনুশীলন?

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

public:
    MyGreatClass(ConfigBlock &config);

অথবা এগুলিতে কেবল একটি শিরোনাম "কোডিংব্লক। H" অন্তর্ভুক্ত করা হয়েছে যাতে আমার কোডিংব্লকের সংজ্ঞা রয়েছে:

extern CodingBlock MyCodingBlock;

তারপরে, কেবল ক্লাস .cpp ফাইলের মধ্যে কনফিগার ব্লক স্টাফ অন্তর্ভুক্ত এবং ব্যবহার করা দরকার।
.H ফাইল শ্রেণীর ব্যবহারকারীর সাথে এই ইন্টারফেসটি প্রবর্তন করে না। যাইহোক, কনফিগারব্লকের ইন্টারফেসটি এখনও আছে, তবে এটি .h ফাইল থেকে লুকানো আছে।

এভাবে লুকিয়ে রাখা কি ভাল?

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

উত্তর:


10

আমি বেশ বাস্তববাদী, তবে এখানে আমার প্রধান উদ্বেগটি হ'ল আপনি ConfigBlockসম্ভবত এটি সম্ভবত আপনার খারাপ ইন্টারফেসের নকশাকে আধিপত্য বিস্তার করতে দিচ্ছেন। আপনার যখন এই জাতীয় কিছু থাকে:

explicit MyGreatClass(const ConfigBlock& config);

... আরও উপযুক্ত ইন্টারফেস এর মত হতে পারে:

MyGreatClass(int foo, float bar, const string& baz);

... এই foo/bar/bazক্ষেত্রগুলিকে প্রচুর পরিমাণে চেরি-বাছাইয়ের বিপরীতে ConfigBlock

অলস ইন্টারফেস ডিজাইন

প্লাস পাশে, এই ধরণের ডিজাইনটি আপনার নির্মাণকারীর জন্য একটি স্থিতিশীল ইন্টারফেস ডিজাইন করা সহজ করে তোলে, যেমন, যেহেতু আপনার যদি নতুন কোনও প্রয়োজনের প্রয়োজন হয় তবে আপনি কেবল ConfigBlockএটিকে লোড করতে পারেন (সম্ভবত কোনও কোড পরিবর্তন ছাড়াই) এবং পরে চেরি- কোনও ধরণের ইন্টারফেস পরিবর্তন ছাড়াই আপনার যা প্রয়োজন নতুন জিনিসগুলি বেছে নিন, কেবলমাত্র প্রয়োগের পরিবর্তন MyGreatClass

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

সুতরাং এখানে অবশ্যই কিছু পক্ষ রয়েছে, তবে এগুলি কনস দ্বারা খুব বেশি ভারী হতে পারে।

সংযোজন

এই দৃশ্যে, ConfigBlockউদাহরণস্বরূপ তৈরি হওয়া এই জাতীয় সমস্ত শ্রেণিগুলির নির্ভরতাগুলি দেখতে এরকম হয়:

এখানে চিত্র বর্ণনা লিখুন

এটি পিটাতে পরিণত হতে পারে, উদাহরণস্বরূপ, যদি আপনি Class2এই চিত্রটিতে বিচ্ছিন্নভাবে পরীক্ষা করতে চান । ConfigBlockপ্রাসঙ্গিক ক্ষেত্রগুলি সহ বিভিন্ন ইনপুটগুলি আপনাকে পর্যাপ্তরূপে অনুকরণ Class2করতে হতে পারে বিভিন্ন শর্তে এটি পরীক্ষা করতে সক্ষম হতে আগ্রহী।

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

পুনর্ব্যাবহার্যোগ্যতা / Deployability / Testability

পরিবর্তে আপনি যদি এই ইন্টারফেসগুলি যথাযথভাবে ডিজাইন করেন তবে আমরা সেগুলি ডিকুয়াল করে এ জাতীয় ConfigBlockকিছু দিয়ে শেষ করতে পারি:

এখানে চিত্র বর্ণনা লিখুন

আপনি যদি এই উপরের চিত্রটিতে লক্ষ্য করেন তবে সমস্ত শ্রেণিগুলি স্বতন্ত্র হয়ে উঠবে (তাদের অভিজাত / বহির্গামী দম্পতিরা 1 দ্বারা হ্রাস পাবে)।

এটি অনেক বেশি স্বতন্ত্র শ্রেণীর দিকে পরিচালিত করে (কমপক্ষে স্বতন্ত্র ConfigBlock) যা নতুন পরিস্থিতিতে / প্রকল্পগুলিতে পুনরায় ব্যবহার / পরীক্ষা করা সহজ হতে পারে।

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

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

উপসংহার

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

সর্বশেষ তবে কম নয়:

extern CodingBlock MyCodingBlock;

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

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


1

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

আমি সি # ব্যবহার করব যেহেতু আমি ভাষাটি আরও ভাল জানি তবে এটি সি ++ এ সহজেই স্থানান্তরিত হওয়া উচিত।

public class ConfigBlock
{
    public ConfigBlock()
    {
        // Load config data and
        // connectionSettings = new ConnectionConfig();
        // connectionSettings...
    }

    private ConnectionConfig connectionSettings;

    public ConnectionConfig GetConnectionSettings()
    {
        return connectionSettings;
    }
}

public class FactoryProvider
{
    public FactoryProvider(ConfigBlock config)
    {
        this.config = config;
    }

    private ConfigBlock config;

    public ConnectionFactory GetConnectionFactory()
    {
        ConnectionConfig connectionSettings = config.GetConnectionSettings();

        return new ConnectionFactory(connectionSettings);
    }
}

public class ConnectionFactory
{
    public ConnectionFactory(ConnectionConfig settings)
    {
        this.settings = settings;
    }

    private ConnectionConfig settings;

    public Connection GetConnection()
    {
        return new Connection(settings.Hostname, settings.Port, settings.Username, settings.Password);
    }
}

এর পরে আপনার এমন কিছু শ্রেণির প্রয়োজন যা "অ্যাপ্লিকেশন" হিসাবে কাজ করে যা আপনার মূল পদ্ধতিতে ইনস্ট্যান্ট হয়ে যায়:

// Your main procedure (yeah I'm bending the rules of C# a tad here,
// but you get the point).
int Main(string[] args)
{
    Application app = new Application();

    app.Run();
}

public class Application
{
    public Application()
    {
        config = new ConfigBlock();
        factoryProvider = new FactoryProvider(config);
    }

    private ConfigBlock config;
    private FactoryProvider factoryProvider;

    public void Run()
    {
        ConnectionFactory connections = factoryProvider.GetConnectionFactory();
        Connection connection = connections.GetConnection();

        connection.Connect();

        // Enter into your main loop and do what this program is meant to do
    }
}

একটি সর্বশেষ নোট হিসাবে, এটি। নেট কথা বলতে "সরবরাহকারী অবজেক্ট" হিসাবে পরিচিত। .NET- এ সরবরাহকারী অবজেক্টগুলি ফ্যাক্টরি অবজেক্টের সাথে কনফিগারেশন ডেটা বিবাহ করে বলে মনে হচ্ছে, যা আপনি এখানে করতে চান তা মূলত।

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

এই প্যাটার্নের সাথে সম্পর্কিত আরও একটি ভাল পঠন: সরবরাহকারী মডেল

শেষ অবধি, এই প্যাটার্নের সমালোচনা: সরবরাহকারী কোনও প্যাটার্ন নয়


সরবরাহকারীর মডেলগুলির লিঙ্কগুলি বাদে সমস্ত কিছুই ভাল। প্রতিবিম্বটি সি ++ দ্বারা সমর্থিত নয় এবং এটি কার্যকর হবে না।
বি

@ বিঃ: সঠিক। শ্রেণীর প্রতিবিম্ব বিদ্যমান নয়, তবে আপনি একটি ম্যানুয়াল ওয়ার্কআরউন্ড তৈরি করতে পারেন যা মূলত একটি switchবিবৃতিতে রূপান্তরিত হয় বা ifকনফিগার ফাইল থেকে পঠিত কোনও মানের বিপরীতে পরীক্ষার পরীক্ষায় পরিণত হয়।
গ্রেগ বার্গার্ট

0

প্রথম প্রশ্ন: এই জাতীয় সমস্ত রানটাইম কনফিগার ডেটা এক শ্রেণিতে সংগ্রহ করা কি ভাল অনুশীলন?

হ্যাঁ. রানটাইমের ধ্রুবক এবং মানগুলি এবং সেগুলি পড়ার জন্য কোডটি কেন্দ্রীভূত করা ভাল।

একটি শ্রেণীর 'কনস্ট্রাক্টর আমার কনফিগারব্লকের একটি প্রদত্ত রেফারেন্স হতে পারে

এটি খারাপ: আপনার বেশিরভাগ নির্মাতার বেশিরভাগ মানের প্রয়োজন হবে না। পরিবর্তে, এমন কিছুর জন্য ইন্টারফেস তৈরি করুন যা নির্মাণের জন্য তুচ্ছ নয়:

পুরানো কোড (আপনার প্রস্তাব):

MyGreatClass(ConfigBlock &config);

নতুন কোড:

struct GreatClassData {/*...*/}; // initialization data for MyGreatClass
GreatClassData ConfigBlock::great_class_values();

একটি মাইগ্রেটক্লাস ইনস্ট্যান্ট করুন:

auto x = MyGreatClass{ current_config_block.great_class_values() };

এখানে, current_config_blockআপনার ConfigBlockশ্রেণীর একটি উদাহরণ রয়েছে (এটির মধ্যে যা আপনার সমস্ত মানকে অন্তর্ভুক্ত করে) এবং MyGreatClassক্লাসটি একটি GreatClassDataউদাহরণ গ্রহণ করে । অন্য কথায়, কেবল তাদের প্রয়োজনীয় ডেটা কনস্ট্রাক্টরকে পাস করুন এবং ConfigBlockসেই ডেটা তৈরি করতে আপনার সুবিধাগুলি যুক্ত করুন।

অথবা এগুলিতে কেবল একটি শিরোনাম "কোডিংব্লক। H" অন্তর্ভুক্ত করা হয়েছে যাতে আমার কোডিংব্লকের সংজ্ঞা রয়েছে:

 extern CodingBlock MyCodingBlock;

তারপরে, কেবল ক্লাস .cpp ফাইলের মধ্যে কনফিগার ব্লক স্টাফ অন্তর্ভুক্ত এবং ব্যবহার করা দরকার। .H ফাইলটি এই ইন্টারফেসটিকে শ্রেণীর ব্যবহারকারীর সাথে পরিচয় করে না। যাইহোক, কনফিগারব্লকের ইন্টারফেসটি এখনও আছে, তবে এটি .h ফাইল থেকে লুকানো আছে। এভাবে লুকিয়ে রাখা কি ভাল?

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

এছাড়াও, আপনার ক্লায়েন্টের ক্লাসগুলি (আপনার MyGreatClass) এর সাথে টাইপ করবেন না CodingBlock; এর অর্থ এই যে, আপনার যদি MyGreatClassএকটি স্ট্রিং এবং পাঁচ পূর্ণসংখ্যার লাগে, আপনি ভাল করে STRING এবং পূর্ণসংখ্যার কথা প্রসঙ্গে বন্ধ হবে, আপনার চেয়ে একটি ক্ষণস্থায়ী হবে CodingBlock


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

0

সংক্ষিপ্ত উত্তর:

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


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

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