সি # তে একটি ইন্টারফেসে কী পূর্ব শর্ত (এলএসপি) নির্দিষ্ট করবেন?


11

ধরা যাক আমাদের নিম্নলিখিত ইন্টারফেস রয়েছে -

interface IDatabase { 
    string ConnectionString{get;set;}
    void ExecuteNoQuery(string sql);
    void ExecuteNoQuery(string[] sql);
    //Various other methods all requiring ConnectionString to be set
}

পূর্বশর্ত হ'ল যে কোনও পদ্ধতি চালানোর আগে কানেকশনস্ট্রিং সেট / ইনটালাইজড করা উচিত।

এই পূর্বশর্তটি কোনও কনস্ট্রাক্টরের মাধ্যমে সংযোগ স্ট্রিং দিয়ে কিছুটা অর্জন করা যেতে পারে যদি আইডিটাবেসটি কোনও বিমূর্ত বা কংক্রিট শ্রেণীর হয় -

abstract class Database { 
    public string ConnectionString{get;set;}
    public Database(string connectionString){ ConnectionString = connectionString;}

    public void ExecuteNoQuery(string sql);
    public void ExecuteNoQuery(string[] sql);
    //Various other methods all requiring ConnectionString to be set
}

বিকল্পভাবে, আমরা সংযোগ তৈরি করতে পারি প্রতিটি পদ্ধতির জন্য একটি পরামিতি স্ট্রিং, তবে এটি কেবল একটি বিমূর্ত শ্রেণি তৈরি করার চেয়ে খারাপ দেখায় -

interface IDatabase { 
    void ExecuteNoQuery(string connectionString, string sql);
    void ExecuteNoQuery(string connectionString, string[] sql);
    //Various other methods all with the connectionString parameter
}

প্রশ্ন -

  1. ইন্টারফেসের মধ্যেই এই পূর্বশর্তটি নির্দিষ্ট করার কোনও উপায় আছে? এটি একটি বৈধ "চুক্তি" তাই আমি ভাবছি যে এর জন্য কোনও ভাষা বৈশিষ্ট্য বা প্যাটার্ন রয়েছে কিনা (বিমূর্ত শ্রেণির সমাধান হ্যাক ইমো আরও দুটি ধরণের তৈরি করার প্রয়োজন ছাড়াও - একটি ইন্টারফেস এবং একটি বিমূর্ত শ্রেণি - প্রতিবার এটি প্রয়োজন)
  2. এটি তাত্ত্বিক কৌতূহল বেশি - এই পূর্বশর্তটি কি আসলে এলএসপির প্রসঙ্গে যেমন পূর্বশর্তের সংজ্ঞায় পড়ে?

2
"এলএসপি" দ্বারা আপনি ছেলেরা লিসকভ প্রতিস্থাপন নীতি সম্পর্কে কথা বলছেন? "যদি এর হাঁসের মতো হাঁসের মতো কিন্তু ব্যাটারির দরকার হয় তবে এটি একটি হাঁসের নয়" নীতি? কারণ আমি এটি দেখতে পেয়েছি এটি আরও বেশি লঙ্ঘন আইএসপি এবং এসআরপি হতে পারে এমনকি ওসিপি কিন্তু সত্যই এলএসপি নয়।
সেবাস্তিয়ান

2
যাতে আপনি কি জানেন, এই পুরো ধারণা "ConnectionString সেট করা আবশ্যক / intialized আগে পদ্ধতি চালানো যেতে পারে কোন" সময়গত কাপলিং একটি উদাহরণ blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling এবং এড়িয়ে চলা উচিত, যদি সম্ভব.
রিচিবান

সুমেন সত্যিই অ্যাবস্ট্রাক্ট ফ্যাক্টরীর বড় ফ্যান।
অ্যাড্রিয়ান ইফটোড

উত্তর:


10
  1. হ্যাঁ. .Net 4.0 উপরের দিকে, মাইক্রোসফ্ট কোড চুক্তি সরবরাহ করে । এগুলি ফর্মের পূর্বশর্ত নির্ধারণ করতে ব্যবহার করা যেতে পারে Contract.Requires( ConnectionString != null );। যাইহোক, একটি ইন্টারফেসের জন্য এই কাজটি করতে, আপনার এখনও একটি সহায়ক শ্রেণীর প্রয়োজন হবে IDatabaseContract, যা এর সাথে সংযুক্ত হয়ে যায় IDatabaseএবং পূর্ববর্তী অবস্থাটি আপনার ইন্টারফেসের প্রতিটি পৃথক পদ্ধতির জন্য সংজ্ঞায়িত করা দরকার যেখানে এটি রাখা উচিত। ইন্টারফেসের জন্য একটি বিস্তৃত উদাহরণের জন্য এখানে দেখুন

  2. হ্যাঁ , এলএসপি একটি চুক্তির সিনট্যাক্টিকাল এবং শব্দার্থক উভয় অংশই নিয়ে কাজ করে।


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

1
@ রবার্ট হার্ভে: হ্যাঁ, আপনি ঠিক বলেছেন। প্রযুক্তিগতভাবে, আপনার অবশ্যই একটি দ্বিতীয় শ্রেণির প্রয়োজন, তবে একবার সংজ্ঞায়িত হয়ে গেলে চুক্তিটি ইন্টারফেসের প্রতিটি প্রয়োগের জন্য স্বয়ংক্রিয়ভাবে কাজ করে।
ডক ব্রাউন

21

সংযোগ এবং অনুসন্ধান দুটি পৃথক উদ্বেগ। এর মতো, তাদের দুটি পৃথক ইন্টারফেস থাকা উচিত।

interface IDatabaseConnection
{
    IDatabase Connect(string connectionString);
}

interface IDatabase
{
    public void ExecuteNoQuery(string sql);
    public void ExecuteNoQuery(string[] sql);
}

এটি উভয়ই নিশ্চিত করে যে IDatabaseব্যবহারের সময় সংযুক্ত হবে এবং ক্লায়েন্টকে এটির প্রয়োজন নেই এমন ইন্টারফেসের উপর নির্ভর করে না।


"এটি ধরণের মাধ্যমে পূর্বশর্ত প্রয়োগের একটি ধরণ" সম্পর্কে আরও স্পষ্ট হতে পারে
কালেথ

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

নির্দিষ্ট requrement যে কিছু আগে ঘটে অন্য কিছু ব্যাপকভাবে প্রযোজ্য। আমিও মনে করি আপনার উত্তর এই প্রশ্নের সাথে আরও ভাল ফিট করে তবে এই উত্তরটির উন্নতি করা যেতে পারে
কালেথ

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

4
@ jpmc26 আপনার আপত্তিগুলির কোনওটিই বোধগম্য নয়, কারণ শ্রেণি প্রয়োগকারী আইডিটাবেজে রাজ্য বজায় রাখা যায়। এটি এটি তৈরি করা প্যারেন্ট ক্লাসকেও উল্লেখ করতে পারে, এভাবে পুরো ডাটাবেস স্থিতিতে অ্যাক্সেস পাওয়া যায়।
ইওফোরিক

5

আসুন একটি পদক্ষেপ পিছনে নিতে এবং এখানে বড় ছবি তাকান।

কি IDatabase'র দায়ভার?

এটির কয়েকটি আলাদা অপারেশন রয়েছে:

  • সংযোগের স্ট্রিং পার্স করুন
  • একটি ডাটাবেসের সাথে একটি সংযোগ খুলুন (একটি বাহ্যিক সিস্টেম)
  • ডাটাবেসে বার্তা প্রেরণ করুন; বার্তাগুলি ডাটাবেসকে তার অবস্থার পরিবর্তন করতে আদেশ দেয় command
  • ডাটাবেস থেকে প্রতিক্রিয়াগুলি গ্রহণ করুন এবং কলার ব্যবহার করতে পারেন এমন ফর্ম্যাটে রূপান্তর করুন
  • সংযোগটি বন্ধ করুন

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

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

নোট করুন যে আমরা একটি রাষ্ট্রীয় প্রোটোকল নিয়ে কাজ করছি তা আপনার দৃ alternative়তার সাথে সর্বশেষ বিকল্পটিকে ছাড়িয়ে যায় (সংযোগের স্ট্রিংটিকে প্যারামিটার হিসাবে পাস করে)।

আমাদের কি সত্যিই সেট করার জন্য সংযোগের স্ট্রিং দরকার?

হ্যাঁ. আপনার সংযোগের স্ট্রিং না হওয়া পর্যন্ত আপনি সংযোগটি খুলতে পারবেন না এবং সংযোগটি না খোলার আগ পর্যন্ত আপনি প্রোটোকল দিয়ে কিছু করতে পারবেন না। সুতরাং এটি ছাড়া কোনও সংযোগের বিষয়টি থাকা অর্থহীন

সংযোগের স্ট্রিংয়ের প্রয়োজনীয়তার সমস্যাটি আমরা কীভাবে সমাধান করব?

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

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

আমাদের কি কোনও ইন্টারফেসের দরকার আছে?

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

আমরা যদি এই রুটে চলে যাই তবে আমাদের কোডটি এর মতো দেখতে পারে:

interface IDatabase {
    void ExecuteNoQuery(string sql);
    void ExecuteNoQuery(string[] sql);
    //Various other methods all requiring ConnectionString to be set
}

abstract class ConnectionStringDatabase : IDatabase { 

    public string ConnectionString { get; }

    public Database(string connectionString) {
        this.ConnectionString = connectionString;
        this.Open();
    }

    protected abstract void Open();

    public abstract void ExecuteNoQuery(string sql);
    public abstract void ExecuteNoQuery(string[] sql);
    //Various other methods all requiring ConnectionString to be set
}

ডাউনভোটার যদি তাদের মতবিরোধের কারণ ব্যাখ্যা করে তবে প্রশংসা করবে।
jpmc26

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

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

তবুও আমি এই upvote।
সেবাস্তিয়ান

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

0

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

public interface IDatabase : IDisposable
{
    string ConnectionString { get; }
    void ExecuteNoQuery(string sql);
    void ExecuteNoQuery(string[] sql);
    //Various other methods all requiring ConnectionString to be set
}

public class SqlDatabase : IDatabase
{
    public string ConnectionString { get; }
    SqlConnection sqlConnection;
    SqlTransaction sqlTransaction; // optional

    public SqlDatabase(string connectionStr)
    {
        if (String.IsNullOrEmpty(connectionStr)) throw new ArgumentException("connectionStr empty");
        ConnectionString = connectionStr;
        instantiateSqlProps();
    }

    private void instantiateSqlProps()
    {
        sqlConnection.Open();
        sqlTransaction = sqlConnection.BeginTransaction();
    }

    public void ExecuteNoQuery(string sql) { /*run query*/ }
    public void ExecuteNoQuery(string[] sql) { /*run query*/ }

    public void Dispose()
    {
        sqlTransaction.Commit();
        sqlConnection.Dispose();
    }

    public void Commit()
    {
        Dispose();
        instantiateSqlProps();
    }
}

ব্যবহারটি এর মতো দেখতে পাওয়া যাবে:

using (IDatabase dbase = new SqlDatabase("Data Source = servername; Initial Catalog = MyDb; Integrated Security = True"))
{
    dbase.ExecuteNoQuery("delete from dbo.Invoices");
    dbase.ExecuteNoQuery("delete from dbo.Customers");
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.