खोज…


एकाकी वस्तु

रूबी स्टैंडर्ड लाइब्रेरी में एक सिंगलटन मॉड्यूल है जो सिंगलटन पैटर्न को लागू करता है। एक सिंगलटन क्लास बनाने के लिए पहला कदम एक क्लास में Singleton मॉड्यूल की आवश्यकता और उसे शामिल करना है:

require 'singleton'

class Logger
  include Singleton
end

यदि आप सामान्य रूप से एक नियमित वर्ग के रूप में इस वर्ग को तत्काल करने की कोशिश करते हैं, तो NoMethodError अपवाद उठाया जाता है। अन्य उदाहरणों को गलती से बनाए जाने से रोकने के लिए निर्माणकर्ता को निजी बनाया जाता है:

Logger.new

#=> NoMethodError: private method `new' called for AppConfig:Class    

इस वर्ग के उदाहरण तक पहुँचने के लिए, हमें instance() का उपयोग करने की आवश्यकता है:

first, second = Logger.instance, Logger.instance
first == second

#=> true

लकड़हारा उदाहरण

require 'singleton'


class Logger
  include Singleton

  def initialize
    @log = File.open("log.txt", "a")
  end

  def log(msg)
    @log.puts(msg)
  end
end

Logger वस्तु का उपयोग करने के लिए:

Logger.instance.log('message 2')

सिंगलटन के बिना शामिल हैं

उपरोक्त सिंगलटन कार्यान्वयन सिंग्लटन मॉड्यूल के समावेश के बिना भी किया जा सकता है। यह निम्नलिखित के साथ प्राप्त किया जा सकता है:

class Logger
  def self.instance
    @instance ||= new
  end
end

जो निम्नलिखित के लिए एक आशुलिपि अंकन है:

class Logger
  def self.instance
    @instance = @instance || Logger.new
  end
end

हालांकि, ध्यान रखें कि सिंगलटन मॉड्यूल का परीक्षण और अनुकूलन किया जाता है, इसलिए आपके सिंगलटन को लागू करने के लिए बेहतर विकल्प है।

देखने वाला

ऑब्जर्वर पैटर्न एक सॉफ्टवेयर डिज़ाइन पैटर्न है, जिसमें एक ऑब्जेक्ट (जिसे subject कहा जाता subject ) अपने आश्रितों ( observers बुलाया जाता subject ) की एक सूची रखता है, और उन्हें किसी भी राज्य के परिवर्तनों के बारे में स्वचालित रूप से सूचित करता है, आमतौर पर उनके तरीकों में से एक को कॉल करके।

रूबी ऑब्जर्वर डिजाइन पैटर्न को लागू करने के लिए एक सरल तंत्र प्रदान करता है। मॉड्यूल Observable ऑब्जर्वेबल ऑब्जेक्ट में किसी भी परिवर्तन के ग्राहक को सूचित करने के लिए तर्क प्रदान करता है।

काम करने के लिए, अवलोकन करने वाले को यह बदलना पड़ता है कि वे पर्यवेक्षकों को बदल दें और सूचित करें।

अवलोकन करने वाली वस्तुओं को एक update() पद्धति लागू करनी होगी, जो ऑब्जर्वर के लिए कॉलबैक होगी।

आइए एक छोटी सी चैट लागू करें, जहां उपयोगकर्ता उपयोगकर्ताओं की सदस्यता ले सकते हैं और जब उनमें से कोई कुछ लिखता है, तो ग्राहक अधिसूचित हो जाते हैं।

require "observer"

class Moderator
  include Observable

  def initialize(name)
    @name = name
  end

  def write
    message = "Computer says: No"
    changed
    notify_observers(message)
  end
end

class Warner
  def initialize(moderator, limit)
    @limit = limit
    moderator.add_observer(self)
  end
end

class Subscriber < Warner
  def update(message)
    puts "#{message}"
  end
end

moderator = Moderator.new("Rupert")
Subscriber.new(moderator, 1)
moderator.write
moderator.write

निम्नलिखित उत्पादन का उत्पादन:

# Computer says: No
# Computer says: No

हमने मॉडरेट वर्ग में write की विधि को दो बार ट्रिगर किया है, अपने ग्राहकों को सूचित करते हुए, इस मामले में सिर्फ एक।

हम जितने अधिक सब्सक्राइबर जोड़ेंगे, उतने अधिक परिवर्तन होंगे।

डेकोरेटर पैटर्न

डेकोरेटर पैटर्न वस्तुओं को एक ही वर्ग की अन्य वस्तुओं को प्रभावित किए बिना व्यवहार जोड़ता है। डेकोरेटर पैटर्न उप-कक्षाएं बनाने के लिए एक उपयोगी विकल्प है।

प्रत्येक डेकोरेटर के लिए एक मॉड्यूल बनाएं। यह दृष्टिकोण वंशानुक्रम की तुलना में अधिक लचीला है क्योंकि आप अधिक संयोजनों में जिम्मेदारियों को मिला सकते हैं और मेल कर सकते हैं। इसके अतिरिक्त, क्योंकि पारदर्शिता सज्जाकारों को पुनरावृत्ति होने की अनुमति देती है, यह असीमित संख्या में जिम्मेदारियों के लिए अनुमति देता है।

मान लें कि पिज्जा क्लास में एक लागत विधि है जो 300 रिटर्न देती है:

class Pizza
  def cost
    300
  end
end

पिज्जा को पनीर की एक अतिरिक्त परत के साथ PizzaWithCheese और लागत 50 से अधिक हो जाती है। सबसे आसान तरीका यह है कि PizzaWithCheese उप-वर्ग बनाएं जो लागत विधि में 350 लौटाता है।

class PizzaWithCheese < Pizza
  def cost
    350
  end
end

अगला, हमें एक बड़े पिज्जा का प्रतिनिधित्व करने की आवश्यकता है जो एक सामान्य पिज्जा की लागत में 100 जोड़ता है। हम पिज्जा के लार्जपाइरा उपवर्ग का उपयोग करके इसका प्रतिनिधित्व कर सकते हैं।

class LargePizza < Pizza
  def cost
    400
  end
end

हमारे पास एक एक्स्ट्रालार्जपाइन्जर भी हो सकता है जो हमारे लार्जपिंजरा को 15 से आगे की लागत देता है। अगर हम विचार करें कि इन पिज्जा प्रकारों को पनीर के साथ परोसा जा सकता है, तो हमें लार्जपाइजरविथचैज और एक्स्ट्रालार्जेज पिज्ज़ाविथेक उपवर्गों को जोड़ना होगा। यह कुल 6 वर्गों के साथ समाप्त होगा।

दृष्टिकोण को सरल बनाने के लिए, पिज्जा क्लास में व्यवहार को गतिशील रूप से जोड़ने के लिए मॉड्यूल का उपयोग करें:

मॉड्यूल + विस्तार + सुपर डेकोरेटर: ->

class Pizza
  def cost
    300
  end
end

module CheesePizza
  def cost
    super + 50
  end
end

module LargePizza
  def cost
    super + 100
  end
end

pizza = Pizza.new         #=> cost = 300
pizza.extend(CheesePizza) #=> cost = 350
pizza.extend(LargePizza)  #=> cost = 450
pizza.cost                #=> cost = 450

प्रतिनिधि

प्रॉक्सी ऑब्जेक्ट का उपयोग अक्सर किसी अन्य ऑब्जेक्ट तक पहरा देने को सुनिश्चित करने के लिए किया जाता है, जो आंतरिक व्यावसायिक तर्क हम सुरक्षा आवश्यकताओं के साथ प्रदूषित नहीं करना चाहते हैं।

मान लीजिए कि हम गारंटी देना चाहते हैं कि विशिष्ट अनुमतियों का केवल उपयोगकर्ता ही संसाधन तक पहुँच सकता है।

प्रॉक्सी परिभाषा: (यह सुनिश्चित करता है कि केवल वे उपयोगकर्ता जो वास्तव में आरक्षण देख सकते हैं उपभोक्ता आरक्षण_ सेवा में सक्षम होंगे)

class Proxy
  def initialize(current_user, reservation_service)
    @current_user = current_user
    @reservation_service = reservation_service
  end

  def highest_total_price_reservations(date_from, date_to, reservations_count)
    if @current_user.can_see_reservations?
      @reservation_service.highest_total_price_reservations(
        date_from, 
        date_to, 
        reservations_count
      )
    else
      []
    end
  end 
end

मॉडल और आरक्षण सेवा:

class Reservation
  attr_reader :total_price, :date

  def initialize(date, total_price)
    @date = date
    @total_price = total_price
  end
end

class ReservationService
  def highest_total_price_reservations(date_from, date_to, reservations_count)
    # normally it would be read from database/external service
    reservations = [
      Reservation.new(Date.new(2014, 5, 15), 100),
      Reservation.new(Date.new(2017, 5, 15), 10),          
      Reservation.new(Date.new(2017, 1, 15), 50)
    ]

    filtered_reservations = reservations.select do |reservation|
      reservation.date.between?(date_from, date_to) 
    end

    filtered_reservations.take(reservations_count)
  end
end        

class User
  attr_reader :name

  def initialize(can_see_reservations, name)
    @can_see_reservations = can_see_reservations
    @name = name
  end

  def can_see_reservations?
    @can_see_reservations
  end
end

ग्राहक सेवा:

class StatsService
  def initialize(reservation_service)
    @reservation_service = reservation_service
  end

  def year_top_100_reservations_average_total_price(year)
    reservations = @reservation_service.highest_total_price_reservations(
      Date.new(year, 1, 1),
      Date.new(year, 12, 31),
      100
    )

    if reservations.length > 0
      sum = reservations.reduce(0) do |memo, reservation| 
        memo + reservation.total_price
      end

      sum / reservations.length
    else
      0
    end
  end
end

परीक्षा:

def test(user, year)
  reservations_service = Proxy.new(user, ReservationService.new)
  stats_service = StatsService.new(reservations_service)
  average_price = stats_service.year_top_100_reservations_average_total_price(year)
  puts "#{user.name} will see: #{average_price}"
end

test(User.new(true, "John the Admin"), 2017)
test(User.new(false, "Guest"),         2017)

लाभ
  • जब एक्सेस प्रतिबंध बदले जाते हैं, तो हम ReservationService में किसी भी बदलाव से बचते हैं।
  • हम व्यापार से संबंधित डेटा (मिश्रण नहीं कर रहे हैं date_from , date_to , reservations_count सेवा में डोमेन असंबंधित अवधारणाओं (उपयोगकर्ता अनुमतियों) के साथ)।
  • उपभोक्ता ( StatsService ) अनुमति संबंधी तर्क से भी मुक्त है

चेतावनियां
  • प्रॉक्सी इंटरफ़ेस हमेशा वैसा ही होता है जैसा कि वह ऑब्जेक्ट छुपाता है, ताकि प्रॉक्सी द्वारा लिपटे हुए सेवा का उपभोग करने वाले उपयोगकर्ता को प्रॉक्सी की उपस्थिति के बारे में पता न चले।


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow