পদ্ধতি চেইন বনাম এনক্যাপসুলেশন


17

"একক অ্যাক্সেস-পয়েন্ট" বনাম পদ্ধতিতে চেইন করার ক্লাসিক ওওপি সমস্যা রয়েছে:

main.getA().getB().getC().transmogrify(x, y)

বনাম

main.getA().transmogrifyMyC(x, y)

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

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

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

উত্তর:


25

আমি মনে করি লিমিটার অফ লিমিটি এতে একটি গুরুত্বপূর্ণ গাইডলাইন সরবরাহ করে (এর সুবিধাগুলি এবং অসুবিধাগুলি সহ, যা যথারীতি প্রতি কেস ভিত্তিতে পরিমাপ করা উচিত)।

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

লিমিটার অফ ডিমিটারের একটি অসুবিধা হ'ল উপাদানগুলির কাছে মেথড কল প্রচারের জন্য মাঝে মাঝে এটি প্রচুর পরিমাণে ছোট "র‍্যাপার" পদ্ধতি লেখার প্রয়োজন হয়। তদুপরি, একটি শ্রেণীর ইন্টারফেস ভারী হয়ে উঠতে পারে কারণ এতে রয়েছে ক্লাসের জন্য পদ্ধতিগুলি হোস্ট করা যায়, ফলস্বরূপ একত্রিত ইন্টারফেস ছাড়াই ক্লাস তৈরি হয়। তবে এটি খারাপ ওও ডিজাইনের একটি চিহ্ন হতে পারে।


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

@ ওক, আমি সুবিধাগুলি এবং অসুবিধাগুলি বর্ণনা করে উদ্ধৃতি যুক্ত করেছি।
পিটার টার্ক

10

আমি সাধারনত পদ্ধতিটিকে শৃঙ্খলা যতটা সম্ভব সীমাবদ্ধ রাখার চেষ্টা করি ( ডেমিটারের ভিত্তিতে )

আমি একমাত্র ব্যতিক্রম সাবলীল ইন্টারফেস / অভ্যন্তরীণ ডিএসএল স্টাইল প্রোগ্রামিংয়ের জন্য।

মার্টিন ফওলার ডোমেন-সুনির্দিষ্ট-ভাষাগুলিতে একই পার্থক্যটি সাজান তবে লঙ্ঘনের কারণে ক্যোয়ারী বিচ্ছেদ লঙ্ঘনের কারণে যা বলে:

যে প্রতিটি পদ্ধতির হয় একটি কমান্ড যা একটি কর্ম সঞ্চালন করা উচিত, বা একটি ক্যোয়ার যা কলার ডেটা ফেরত, কিন্তু উভয় না।

Page০ পৃষ্ঠায় তাঁর বইয়ে ফাউলার বলেছেন:

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


3

আমি মনে করি যে প্রশ্নটি আপনি উপযুক্ত বিমূর্ত ব্যবহার করছেন কিনা।

প্রথম ক্ষেত্রে, আমাদের আছে

interface IHasGetA {
    IHasGetB getA();
}

interface IHasGetB {
    IHasGetC getB();
}

interface IHasGetC {
    ITransmogrifyable getC();
}

interface ITransmogrifyable {
    void transmogrify(x,y);
}

যেখানে প্রধান টাইপ হয় IHasGetA। প্রশ্নটি: এটি কি বিমূর্ততা উপযুক্ত? উত্তর তুচ্ছ নয়। এবং এই ক্ষেত্রে এটি কিছুটা বন্ধ দেখায়, তবে এটি কোনওভাবেই তাত্ত্বিক উদাহরণ। তবে ভিন্ন উদাহরণ তৈরি করতে:

main.getA(v).getB(w).getC(x).transmogrify(y, z);

এর চেয়ে প্রায়শই ভাল

main.superTransmogrify(v, w, x, y, z);

কারণ আধুনিক উদাহরণে উভয় thisএবং mainধরনের উপর নির্ভর করে v, w, x, yএবং z। এছাড়াও, কোডটি আসলে খুব বেশি ভাল দেখাচ্ছে না, যদি প্রতিটি পদ্ধতির ঘোষণায় আধা ডজন আর্গুমেন্ট থাকে।

কোনও পরিষেবা লোকেটারের পক্ষে প্রথম পদ্ধতির প্রয়োজন। আপনি সার্ভিস লোকেটারের মাধ্যমে তৈরি করা ইনস্ট্যান্সটি অ্যাক্সেস করতে চান না।

সুতরাং কোনও বস্তুর মাধ্যমে "পৌঁছনো" অনেক বেশি নির্ভরশীলতা তৈরি করতে পারে, যদি তা প্রকৃত শ্রেণির বৈশিষ্ট্যের উপর ভিত্তি করে হয়।
তবে একটি বিমূর্ততা তৈরি করা, এটি কেবল কোনও অবজেক্ট সরবরাহ করা সম্পূর্ণ ভিন্ন জিনিস।

উদাহরণস্বরূপ, আপনি থাকতে পারেন:

class Main implements IHasGetA, IHasGetA, IHasGetA, ITransmogrifyable {
    IHasGetB getA() { return this; }
    IHasGetC getB() { return this; }
    ITransmogrifyable getC() { return this; }
    void transmogrify(x,y) {
        return x + y;//yeah!
    }
}

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


পরামিতিগুলির সংখ্যা বৃদ্ধি সম্পর্কে খুব আকর্ষণীয় পয়েন্ট।
ওক

2

Demeter আইন , যেমন @ পিটার Török তুলে ধরে, "কম্প্যাক্ট" ফর্ম দাড়ায়।

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


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

1
@ ওক: অন্ধভাবে কিছু করা কখনই ভাল হয় না। একজনের পক্ষে প্রমাণ এবং ভিত্তিতে সিদ্ধান্ত নেওয়া দরকার। এর মধ্যে ডেমিটারের আইনও অন্তর্ভুক্ত রয়েছে।
সিজারগন

2

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

অন্যদিকে, ক্লাসগুলি যেগুলি কেবল "পাশ দিয়ে যায়" পদ্ধতিগুলি থাকার অর্থ হ'ল একাধিক পদ্ধতির একাধিক স্থানে ঘোষণার একটি ওভারহেড।

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


1

আমি প্রায়শই দেখতে পাই যে কোনও প্রোগ্রামের যুক্তিটি শৃঙ্খলাবদ্ধ পদ্ধতিগুলির সাথে ছাঁটাই করা সহজ। আমার কাছে, customer.getLastInvoice().itemCount()আমার মস্তিষ্কের চেয়ে ভাল ফিট করে customer.countLastInvoiceItems()

অতিরিক্ত কাপলিংয়ের রক্ষণাবেক্ষণের মাথাব্যথাটি আপনার পক্ষে নির্ভরযোগ্য। (আমি ছোট ক্লাসেও ছোট ছোট ফাংশন পছন্দ করি, তাই আমি চেইন প্রবণতা করি I'm আমি এটি ঠিক বলছি না - এটি আমি যা করি ঠিক তাই করি))


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