2012-02-20 8 views
8

में रिपोजिटरी या गेटवे पैटर्न रूबी में रिपोजिटरी या गेटवे पैटर्न को कैसे कार्यान्वित कर सकता हूं?रूबी

मैं एक सी # दुनिया से आते हैं और मैं आमतौर पर दूर सार अपने डेटा का उपयोग कर सकते लेकिन ActiveRecord के साथ रूबी में डिफ़ॉल्ट डेटा का उपयोग तंत्र के रूप में, यह स्पष्ट नहीं है कि पूरा करने के लिए कैसे।

क्या मैं आमतौर पर सी # में करना होगा सार इंटरफेस के साथ काम है और फिर EFCustomerRepository, NHibernateCustomerRepository और InMemoryCustomerRepository और स्थिति मैं मिलान ठोस कार्यान्वयन इंजेक्षन पर निर्भर करता है के लिए एक ठोस कार्यान्वयन है।

तो अब, रूबी तरीका क्या है ?!

जहाँ तक मुझे यह समझ के रूप में, गतिशील भाषाओं में आप डि (निर्भरता इंजेक्शन) की तरह कुछ की जरूरत नहीं होगी। और रूबी में मज़ेदार जैसी चीजों की अनुमति देने के लिए शक्तिशाली भाषा विशेषताएं हैं।

लेकिन आप mixin वर्ग या मॉड्यूल-स्तर पर स्थिर उपयोग करने के लिए परिभाषित करेंगे?

मैं अपने व्यवसाय तर्क कैसे लिख सकता हूँ कि अगर मैं एक में स्मृति भंडार के खिलाफ विकसित करना चाहते हैं और उत्पादन में मैं अपने ActiveRecord-भंडार के लिए स्विच होगा?

तो गलत रास्ते पर यहाँ हो सकता है के बाद से मैं एक स्थिर टाइप किया भाषा में सोच करने के लिए इस्तेमाल कर रहा हूँ। किसी को इस काम से रूबी तरीके से कैसे निपटना होगा? असल में मैं अपनी दृढ़ता परत सार बनाना चाहता हूं और यह कार्यान्वयन अदलाबदल करने योग्य है।

संपादित करें: मैं किसी भी मदद के लिए करने के लिए robert c. martins (unclebob) keynote about architecture

धन्यवाद जिक्र कर रहा हूँ ...

+0

http://lancecarlson.github.com/2012/05/15/dci-and-decoupling-business-logic-from-ruby-on-rails.html यह ऐसा कुछ है जो किसी ने किया अंकल बॉब लेख की प्रतिक्रिया। और भी आने को है। – SpoBo

+0

मैं एक मणि की तलाश भी कर रहा हूं जो भंडार पैटर्न लागू करता है। – Andrew

उत्तर

2

खैर, ActiveRecord पहले से ही सार हठ परत प्रदान करता है - several different adapters यह अलग डेटाबेस बैकेंड उपयोग करने की अनुमति है यह। साथ ही, यह ओपन-सोर्स है इसलिए आप यह देखने के लिए स्वतंत्र हैं कि यह कैसे हासिल किया गया है।

पहली नज़र करने पर आप देख सकते हैं यह भी एक AbstractAdapter है कि अन्य सभी एडेप्टर के वारिस है, तथापि, के रूप में रूबी गतिशील है, बतख टाइपिंग भाषा, AbstractAdapter सार तरीकों जो बच्चों में ओवरराइड कर दिया जाएगा शामिल करने के लिए नहीं है कक्षाएं, न तो "अनुबंध" को परिभाषित करती हैं जिन्हें उन्हें सम्मानित करना चाहिए।

संपादित करें:

यहाँ कैसे आप दूर सार रूबी में अपने भंडारण, नहीं यकीन है कि वास्तव में यह है सकता है जो तर्ज पर एक सरल स्केच है:

# say you have an AR model of a person 
class Person < ActiveRecord::Base 
end 

# and in-memory store of persons (simply, a hash) 
IN_MEMORY_STORE = { 
    :Person => ['Tim', 'Tom', 'Tumb'] 
} 

# this will abstract access 
class MyAbstractModel 
    def initialize item, adapter 
    @item = item 
    @adapter = adapter 
    end 

    # get all elements from the store 
    def all 
    case @adapter 
    when :active_record 
     # pull from database: 
     Object.const_get(@item).all 
    when :in_memory_store 
     # get from in-memory store 
     IN_MEMORY_STORE[@item] 
    else 
     raise "Unknown adapter" 
    end 
    end 
end 

# get all Persons from in-memory storage... 
p MyAbstractModel.new(:Person, :in_memory_store).all 
# ...and from a database 
p MyAbstractModel.new(:Person, :active_record).all 
+0

उत्तर के लिए धन्यवाद ... मैं सोच रहा था कि बतख-टाइपिंग भाषा इस तरह की चीजों को कैसे संभालती है ... और मैं ढांचे से कैसे स्वतंत्र रहूंगा, इसलिए यदि एक दिन ActiveRecord अब प्रचार नहीं कर रहा है और वहां एक नया बच्चा है ब्लॉक मैं आसानी से स्विच करने में सक्षम हो जाएगा ... –

+0

ऐसा इसलिए नहीं है क्योंकि यह 'ब्लॉक पर नया बच्चा' है जिसका आपको बिल्कुल उपयोग करना है ... आप उन तकनीकों का उपयोग करना जारी रख सकते हैं जो अब प्रचार नहीं कर रहे हैं और अभी भी "अच्छा" सॉफ्टवेयर बनाओ। –

1

@serverinfo, मैं के बारे में ज्यादा पता नहीं है सी#। लेकिन जब मैं जावा/सी पृष्ठभूमि से रूबी आया, तो मुझे पता चला कि मुझे यह समझ में आया कि यह भाषा वास्तव में कितनी लचीली है। आप कहते हैं कि यहां आपकी असली समस्या है "अपनी दृढ़ता परत को दूर करें और इसे विनिमय योग्य बनाएं"। आपने यह भी पूछा कि "मैं व्यवसाय तर्क कैसे लिखूंगा"।

मेरा सुझाव है कि आप अपनी पूर्वकल्पनाओं को फेंक दें और खुद से पूछें: " कैसे मेरे व्यापार तर्क परत के भीतर डेटा एक्सेस/स्टोरेज व्यक्त करने के लिए"? इस बारे में चिंता न करें कि आप क्या सोच सकते हैं या नहीं किया जा सकता है; यदि आप यह समझ सकते हैं कि काम करने के लिए इंटरफ़ेस कैसे है, तो शायद रूबी में ऐसा किया जा सकता है।

आपको यह भी तय करना होगा कि आप उपयोग किए जाने वाले ठोस कार्यान्वयन को कैसे निर्दिष्ट करना चाहते हैं। क्या यह संभव है कि आप अलग-अलग मॉडल ऑब्जेक्ट्स के लिए एक अलग डेटा स्टोर का उपयोग करना चाहें? क्या आप रन-टाइम पर स्विच करना चाहते हैं? क्या आप कॉन्फ़िगरेशन फ़ाइल में या कोड में उपयोग किए जाने वाले बैकएंड को निर्दिष्ट करना चाहते हैं? यदि आप यह तय कर सकते हैं कि करना चाहते हैं, तो स्टैक ओवरफ़्लो पर बहुत से लोग हैं जो को को समझने में आपकी सहायता कर सकते हैं।

+0

हाँ उत्तर के लिए धन्यवाद ... मैं इसे समझने की कोशिश कर रहा था: http://confreaks.com/videos/759-rubymidwest2011-keynote-architecture-the-lost-years ... और आप सही मायने में दिमागी - लेकिन अच्छा =) –

3

मैं जो कह रहा हूं उसे प्राप्त करता हूं। मैं एक .NET पृष्ठभूमि से भी आ रहा हूं। अपने व्यापार तर्क को दूर करना & दृढ़ता तर्क आईएमओ एक अच्छा विचार है। मुझे एक मणि नहीं मिला है जो अभी तक आपके लिए करता है। लेकिन आप आसानी से कुछ सरल बना सकते हैं। अंत में एक भंडार पैटर्न मूल रूप से एक वर्ग है जो आपकी दृढ़ता परत पर प्रतिनिधि होता है।

require 'active_support/core_ext/module/attribute_accessors' 

class GenericRepository 

    def initialize(options = {}) 
    @scope = options[:scope] 
    @association_name = options[:association_name] 
    end 

    def self.set_model(model, options = {}) 
    cattr_accessor :model 
    self.model = model 
    end 

    def update(record, attributes) 
    check_record_matches(record) 
    record.update_attributes!(attributes) 
    end 

    def save(record) 
    check_record_matches(record) 
    record.save 
    end 

    def destroy(record) 
    check_record_matches(record) 
    record.destroy 
    end 

    def find_by_id(id) 
    scoped_model.find(id) 
    end 

    def all 
    scoped_model.all 
    end 

    def create(attributes) 
    scoped_model.create!(attributes) 
    end 

private 

    def check_record_matches(record) 
    raise(ArgumentError, "record model doesn't match the model of the repository") if not record.class == self.model 
    end 

    def scoped_model 
    if @scope 
     @scope.send(@association_name) 
    else 
     self.model 
    end 
    end 

end 

और फिर आप उदाहरण के लिए एक पोस्ट भंडार हो सकता है:

यहाँ मैं क्या कर रहा है।

class PostRepository < GenericRepository 

    set_model Post 

    # override all because we also want to fetch the comments in 1 go. 
    def all 
    scoped_model.all(:include => :comments) 
    end 

    def count() 
    scoped_model.count 
    end 

end 

बस इसे अपने नियंत्रक में पहले_फिल्टर में प्रारंभ करें या आरंभ करें या कहीं भी। इस मामले में मैं इसे current_user पर स्कॉप कर रहा हूं ताकि यह केवल उन रिकॉर्ड्स को प्राप्त कर सके और स्वचालित रूप से केवल वर्तमान उपयोगकर्ता के लिए पोस्ट बनाएं।

def initialize 
    @post_repository = PostRepository.new(:scope => @current_user, :association_name => 'posts') 
end 

def index 
    @posts = @post_repository.all 
    respond_with @posts, :status => :ok 
end 

मैं https://github.com/bkeepers/morphine पर आया जो कि एक छोटा डी ढांचा है। यह आपके लिए काम कर सकता है :) लेकिन डीआई रूबी में भारी इस्तेमाल नहीं किया गया पैटर्न है। साथ ही, मैं अपने रिपो को तत्काल उपयोगकर्ता या किसी अन्य चीज़ पर दायरा देने के लिए तत्काल करता हूं।

मैं जो कुछ भी पूछता हूं उसे करने का सही तरीका खोजने के लिए एक खोज पर हूं और अगर मुझे कभी पता चलता है तो इसके बारे में थोड़ा सा लिखना है। लेकिन अभी के लिए यह मेरे नियंत्रकों को लगातार & के बीच साफ कटौती करने के लिए पर्याप्त है। यदि यह ठीक से किया जाता है तो बाद में किसी अन्य सिस्टम पर स्विच करने में बड़ी परेशानी नहीं होगी। या कैशिंग आदि जोड़ें

+0

मुझे ऊपर वर्णित तरीके पसंद आया और मैंने अपने ऐप में इसे लागू करने का प्रयास किया। लेकिन मैं डेटाबेस कनेक्शन और ActiveRecord सामान कहां डाल/जोड़ने के लिए अटक गया? क्या आप उपरोक्त को एक सरल ActiveRecord/sqlite3 डीबी कनेक्शन और विधियों के साथ बढ़ा सकते हैं? – Autodidact