রেলস: ডিমিটার বিভ্রান্তির আইন


13

আমি রেলস অ্যান্টিপ্যাটার্নস নামে একটি বই পড়ছি এবং তারা ডেমিটারের আইন ভঙ্গ না করার জন্য প্রতিনিধিদের ব্যবহার করার বিষয়ে কথা বলছে talk এখানে তাদের প্রধান উদাহরণ:

তারা বিশ্বাস করে যে কন্ট্রোলারে এই জাতীয় কিছু কল করা খারাপ (এবং আমি সম্মত)

@street = @invoice.customer.address.street

তাদের প্রস্তাবিত সমাধান নিম্নলিখিত কাজগুলি করা:

class Customer

    has_one :address
    belongs_to :invoice

    def street
        address.street
    end
end

class Invoice

    has_one :customer

    def customer_street
        customer.street
    end
end

@street = @invoice.customer_street

তারা উল্লেখ করছে যে যেহেতু আপনি কেবল একটি বিন্দু ব্যবহার করেন তাই আপনি এখানে ডেমিটারের আইন ভঙ্গ করছেন না। আমি মনে করি এটি ভুল, কারণ আপনি এখনও চালকের রাস্তা পেতে ঠিকানার মাধ্যমে গ্রাহকের মধ্য দিয়ে যাচ্ছেন। আমি প্রাথমিকভাবে আমার পড়া ব্লগ পোস্ট থেকে এই ধারণাটি পেয়েছি:

http://www.dan-manges.com/blog/37

ব্লগ পোস্টে প্রধান উদাহরণটি হ'ল

class Wallet
  attr_accessor :cash
end
class Customer
  has_one :wallet

  # attribute delegation
  def cash
    @wallet.cash
  end
end

class Paperboy
  def collect_money(customer, due_amount)
    if customer.cash < due_ammount
      raise InsufficientFundsError
    else
      customer.cash -= due_amount
      @collected_amount += due_amount
    end
  end
end

ব্লগ পোস্টে উল্লেখ করা হয়েছে যে এর customer.cashপরিবর্তে কেবল একটি বিন্দু customer.wallet.cashথাকলেও এই কোডটি এখনও ডেমিটারের আইন লঙ্ঘন করে।

এখন পেপারবয় সংগ্রহে_মনি পদ্ধতিতে, আমাদের কাছে দুটি বিন্দু নেই, কেবল আমাদের "গ্রাহক.ক্যাশ" আছে have এই প্রতিনিধি দল কি আমাদের সমস্যার সমাধান করেছে? একেবারেই না. যদি আমরা আচরণটি দেখি তবে একটি কাগজপোকুই নগদ আউট পাওয়ার জন্য সরাসরি কোনও গ্রাহকের মানিব্যাগের কাছে পৌঁছে যাচ্ছে।

সম্পাদনা

আমি সম্পূর্ণরূপে বুঝতে পারি এবং সম্মত হয়েছি যে এটি এখনও লঙ্ঘন এবং আমি Walletআমার কাছে অর্থ প্রদানের ব্যবস্থা করে এবং আমাকে Customerক্লাসের অভ্যন্তরে সেই পদ্ধতিটি কল করা উচিত বলে প্রত্যাহারের নামে একটি পদ্ধতি তৈরি করতে হবে । আমি যা পাই না তা হ'ল এই প্রক্রিয়া অনুসারে, আমার প্রথম উদাহরণটি এখনও ডেমিটারের আইন লঙ্ঘন করে কারণ Invoiceএখনও Customerরাস্তাটি পেতে সরাসরি প্রবেশ করছে।

কেউ কি আমাকে বিভ্রান্তি দূর করতে সাহায্য করতে পারে? আমি গত 2 দিন ধরে এই বিষয়টিকে ডুবে যাওয়ার চেষ্টা করছি, তবে এটি এখনও বিভ্রান্তিকর।


2
অনুরূপ প্রশ্ন এখানে
Thorsten müller

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

উত্তর:


24

আপনার প্রথম উদাহরণটি ডেমিটারের আইন লঙ্ঘন করে না । হ্যাঁ, কোড সহ যেমন আছে তেমনি বললেন @invoice.customer_streetএকই পেতে ঘটবে মান করে একটি প্রকল্পিত @invoice.customer.address.streetকিন্তু হবে ট্র্যাভেরসাল প্রতিটি পদে পদে, ফিরে মান বস্তু হচ্ছে দ্বারা সিদ্ধান্ত নেওয়া হয় জিজ্ঞাসা - এটি যে "মধ্যে paperboy পৌছানোর নয় গ্রাহকের ওয়ালেট ", এটি" পেপারবয় গ্রাহককে নগদ জিজ্ঞাসা করে, এবং গ্রাহক তাদের মানিব্যাগ থেকে নগদ পেতে "হয়।

যখন আপনি বলবেন @invoice.customer.address.street, আপনি ক্রেতা ও ঠিকানা অভ্যন্তরীণ জ্ঞান অভিমানী করছি - এই খারাপ জিনিস। আপনি যখন বলেন @invoice.customer_street, আপনি জিজ্ঞাসা করছেন invoice, "আরে, আমি গ্রাহকের রাস্তায় চাই, আপনি কীভাবে তা পাবেন তা স্থির করুন "। এর পরে গ্রাহক তার ঠিকানায় বলেন, "আরে আমি আপনার রাস্তায় চাই, আপনি কীভাবে এটি পাবেন তা স্থির করুন "।

ডেমিটারের থ্রাস্ট নয় যে 'আপনি গ্রাফের থেকে খুব দূরের কোনও বস্তুর কাছ থেকে মানগুলি জানতে পারবেন না "; পরিবর্তে এটি' মানগুলি অর্জনের জন্য আপনি নিজে অবজেক্টের গ্রাফের সাথে খুব বেশি অতিক্রম করবেন না '।

আমি সম্মত হ'ল এটি একটি সূক্ষ্ম পার্থক্যের মতো মনে হতে পারে তবে এটি বিবেচনা করুন: ডেমিটার-কমপ্লায়েন্ট কোডে, পরিবর্তনের অভ্যন্তরীণ প্রতিনিধিত্ব করার সময় কত কোড addressপরিবর্তন করা দরকার? নন-ডিমিটার-কমপ্লায়েন্ট কোড সম্পর্কে কী?


আমি ঠিক এই ধরণের ব্যাখ্যার সন্ধান করছিলাম! ধন্যবাদ.
ব্যবহারকারী 2158382

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

2

প্রথম উদাহরণ এবং দ্বিতীয়টি আসলে খুব একটা নয়। প্রথম "একটি বিন্দু" এর নিয়মাবলী সম্পর্কে কথা বলার পরে, দ্বিতীয়টি ওও ডিজাইনে অন্যান্য বিষয় সম্পর্কে আরও বেশি কথা বলে, বিশেষত " বলুন, জিজ্ঞাসা করবেন না "

ডেমিটার লিমিটেড লঙ্ঘন এড়াতে ডেলিগেশন একটি কার্যকর কৌশল, তবে কেবল আচরণের জন্য, গুণাবলীর জন্য নয়। - দ্বিতীয় উদাহরণ থেকে ড্যানের ব্লগ

আবার, " কেবল আচরণের জন্য, গুণাবলীর জন্য নয় "

আপনি যদি গুণাবলী জিজ্ঞাসা করেন, আপনাকে জিজ্ঞাসা করার কথা । "আরে ছেলে, তোমার পকেটে কত টাকা আছে? আমাকে দেখাও, আমি যদি মূল্য দিতে পারো তবে মূল্যায়ন করব।" এটি ভুল, কোনও শপিং ক্লার্ক এ জাতীয় আচরণ করবে না। পরিবর্তে, তারা বলবে, "দয়া করে প্রদান করুন"

customer.pay(due_amount)

তার মূল্য পরিশোধ করা উচিত এবং যদি তিনি অর্থ প্রদান করতে পারেন তবে মূল্যায়ন করা গ্রাহকের নিজস্ব দায়িত্ব হবে। এবং ক্লার্কের কাজ গ্রাহককে প্রদানের কথা বলার পরে শেষ হয়েছে।

সুতরাং, দ্বিতীয় উদাহরণটি কি প্রথমটি ভুল প্রমাণ করে?

আমার মতে. না , যতক্ষণ না:

1. আপনি স্ব-বাধা দিয়ে এটি করেন।

আপনি যখন @invoiceপ্রতিনিধি দ্বারা গ্রাহকের সমস্ত বৈশিষ্ট্য অ্যাক্সেস করতে পারবেন তবে আপনার সাধারণ ক্ষেত্রে এটি খুব কমই প্রয়োজন।

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

#customer-info
  = @invoice.customer_name
  = @invoice.customer_address
  ....

এটা ভুল এবং অদক্ষ। একটি ভাল পদ্ধতির হয়

#customer-info
  = render partial: 'invoice_header_customer', 
           locals: {customer: @invoice.customer}

তারপরে গ্রাহককে সমস্ত বৈশিষ্ট্যগুলি গ্রাহকের অন্তর্ভুক্ত করে প্রক্রিয়া করতে আংশিক হতে দিন।

সুতরাং সাধারণত আপনার প্রয়োজন হয় না। তবে আপনার কাছে সাম্প্রতিক সমস্ত চালানগুলি দেখানোর জন্য একটি তালিকা পৃষ্ঠা থাকতে পারে, প্রতিটি liগ্রাহকের নাম প্রদর্শন করে একটি ব্রিফিং ক্ষেত্র রয়েছে । এই ক্ষেত্রে, আপনার গ্রাহকের বৈশিষ্ট্যটি দেখানোর দরকার নেই এবং এটি টেমপ্লেটটি কোড করা সম্পূর্ণরূপে বৈধ

= @invoice.customer_name

২. এই পদ্ধতি কলের উপর নির্ভর করে আর কোনও পদক্ষেপ নেই।

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


0

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

class Wallet
  attr_accessor :cash
  def withdraw(amount)
     raise InsufficientFundsError if amount > cash
     cash -= amount
     amount
  end
end
class Customer
  has_one :wallet
  # behavior delegation
  def pay(amount)
    @wallet.withdraw(amount)
  end
end
class Paperboy
  def collect_money(customer, due_amount)
    @collected_amount += customer.pay(due_amount)
  end
end

সুতরাং আমি মনে করি আপনার দ্বিতীয় রেফারেন্স আরও সহায়ক পরামর্শ দিচ্ছে।

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


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

0

ড্যানের মতো শব্দগুলি এই নিবন্ধটি থেকে তার উদাহরণটি পেয়েছে: দ্য পেপারবয়, দ্য ওয়ালেট, এবং ল অফ ডিমিটারের

পরিমাপের আইন কোনও অবজেক্টের একটি পদ্ধতিতে কেবল নিম্নলিখিত ধরণের অবজেক্টের পদ্ধতি অনুসরণ করা উচিত:

  1. নিজেই
  2. এর পরামিতি
  3. এটি যে কোনও বস্তু তৈরি করে / ইনস্ট্যান্টিয়েট করে
  4. এটির প্রত্যক্ষ উপাদানসমূহ

কখন এবং কীভাবে ডেমিটারের আইন প্রয়োগ করবেন

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

  1. জড়িত 'গেট' স্টেটমেন্টস - লিমিটার অফ ডেমিটার প্রয়োগ করার প্রথম, সবচেয়ে স্পষ্ট জায়গা হ'ল কোডের জায়গা যা বারবার get() বিবৃতি দিয়েছে,

    value = object.getX().getY().getTheValue();

    যেনে যখন এই উদাহরণের জন্য আমাদের সাধারণ ব্যক্তিকে পুলিশ দ্বারা টেনে আনে, আমরা দেখতে পাই:

    license = person.getWallet().getDriversLicense();

  2. প্রচুর 'অস্থায়ী' অবজেক্ট - কোডটির মতো দেখায় উপরের লাইসেন্সের উদাহরণটি এর চেয়ে ভাল হবে না,

    Wallet tempWallet = person.getWallet(); license = tempWallet.getDriversLicense();

    এটি সমতুল্য, তবে এটি সনাক্ত করা শক্ত।

  3. অনেক শ্রেণি আমদানি করা - আমি যে জাভা প্রকল্পটিতে কাজ করি তাতে আমাদের একটি নিয়ম রয়েছে যে আমরা কেবলমাত্র আমরা ব্যবহৃত ক্লাসগুলি আমদানি করি; আপনি কখনও এরকম কিছু দেখেন না

    import java.awt.*;

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

আমি বুঝতে পারি যে আপনার উদাহরণটি রুবিতে রয়েছে তবে এটি সমস্ত ওওপি ভাষায় প্রয়োগ করা উচিত।

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