2014-04-04 4 views
11

मैं एक खेल विकसित कर रहा हूँ! स्लैक 2.0 के साथ स्कैला में 2.2 एप्लिकेशन और अब मैं केक पैटर्न का उपयोग करने की कोशिश कर रहा हूं, डेटा एक्सेस पहलू से निपट रहा हूं। यह आशाजनक प्रतीत होता है लेकिन मुझे वास्तव में ऐसा लगता है कि मुझे वास्तव में कुछ सरल प्राप्त करने के लिए कक्षाओं/गुणों/वस्तुओं का एक बड़ा समूह लिखना होगा। तो मैं इस पर कुछ प्रकाश का उपयोग कर सकता था।स्कैला स्लिम केक पैटर्न: 9 000 से अधिक कक्षाएं?

एक User अवधारणा के साथ एक बहुत ही सरल उदाहरण लें तो जिस तरह से मैं समझता हूँ कि यह है कि हम होना चाहिए:

case class User(...) //model 

class Users extends Table[User]... //Slick Table 

object users extends TableQuery[Users] { //Slick Query 
//custom queries 
} 

अब तक यह पूरी तरह से उचित है। अब हम एक "केक Patternable" UserRepository जोड़ें:

trait UserRepository { 
val userRepo: UserRepository 
class UserRepositoryImpl { 
    //Here I can do some stuff with slick 
    def findByName(name: String) = { 
     users.withFilter(_.name === name).list 
    } 
    } 
} 

फिर हम एक UserService:

trait UserService { 
this: UserRepository => 
val userService: UserService 
class UserServiceImpl { // 
    def findByName(name: String) = { 
     userRepo.findByName(name) 
    } 
    } 
} 

अब हम एक वस्तु में इस सब के मिश्रण:

object UserModule extends UserService with UserRepository { 
    val userRepo = new UserRepositoryImpl 
    val userService = new UserServiceImpl 
} 
  1. UserRepository वास्तव में उपयोगी है? मैं Users स्लिम ऑब्जेक्ट में कस्टम क्वेरी के रूप में findByName लिख सकता था।

  2. मान लें कि मेरे पास Customer के लिए इस तरह के वर्गों का एक और सेट है, और मुझे इसमें कुछ UserService सुविधाएं उपयोग करने की आवश्यकता है।

मुझे क्या करना चाहिए:

CustomerService { 
this: UserService => 
... 
} 

या

CustomerService { 
val userService = UserModule.userService 
... 
} 
+0

9000 से कहां से मिला? – Blankman

+0

@ ब्लैंकमैन http://knowyourmeme.com/memes/its-over-9000 – user1498572

उत्तर

10

ठीक है, अच्छा लक्ष्यों की तरह उन ध्वनि:

डेटाबेस पुस्तकालय (चालाक अधिक
  • सार, .. ।

    trait UserRepository { 
        type User 
        def findByName(name: String): User 
    } 
    
    // Implementation using Slick 
    trait SlickUserRepository extends UserRepository { 
        case class User() 
        def findByName(name: String) = { 
         // Slick code 
        } 
    } 
    
    // Implementation using Rough 
    trait RoughUserRepository extends UserRepository { 
        case class User() 
        def findByName(name: String) = { 
         // Rough code 
        } 
    } 
    
    फिर CustomerRepository के लिए

    तुम कर सकते हो:)

  • लक्षण इकाई परीक्षण योग्य

आप कुछ इस तरह कर सकता है बनाओ

trait CustomerRepository { this: UserRepository => 
} 

trait SlickCustomerRepository extends CustomerRepository { 
} 

trait RoughCustomerRepository extends CustomerRepository { 
} 

और उन्हें अपने बैकएंड के आधार पर गठबंधन सनकी:

object UserModuleWithSlick 
    extends SlickUserRepository 
    with SlickCustomerRepository 

object UserModuleWithRough 
    extends RoughUserRepository 
    with RoughCustomerRepository 
,210

तुम इतनी तरह इकाई-परीक्षण योग्य वस्तुओं बना सकते हैं:

object CustomerRepositoryTest extends CustomerRepository with UserRepository { 
    type User = // some mock type 
    def findByName(name: String) = { 
     // some mock code 
    } 
} 

आप का पालन करने के

trait CustomerRepository { this: UserRepository => 
} 

object Module extends UserRepository with CustomerRepository 

और

trait CustomerRepository { 
    val userRepository: UserRepository 
    import userRepository._ 
} 

object UserModule extends UserRepository 
object CustomerModule extends CustomerRepository { 
    val userRepository: UserModule.type = UserModule 
} 

के बीच एक मजबूत समानता है कि वहाँ सही हैं यह वह जगह है पुरानी विरासत/एकत्रीकरण व्यापार, स्कैला दुनिया के लिए अद्यतन किया गया। प्रत्येक दृष्टिकोण के फायदे और नुकसान होते हैं। मिश्रण गुणों के साथ, आप कम कंक्रीट ऑब्जेक्ट्स बनाएंगे, जो ट्रैक रखने में आसान हो सकते हैं (जैसा ऊपर है, आपके पास केवल उपयोगकर्ताओं और ग्राहकों के लिए अलग-अलग ऑब्जेक्ट्स की बजाय Module ऑब्जेक्ट है)। दूसरी तरफ, ऑब्जेक्ट निर्माण समय पर लक्षणों को मिश्रित किया जाना चाहिए, इसलिए आप उदाहरण के लिए मौजूदा UserRepository नहीं ले सकते हैं और CustomerRepository इसे मिश्रण करके बना सकते हैं - यदि आपको ऐसा करने की आवश्यकता है, तो आपको एकत्रीकरण का उपयोग करना होगा। ध्यान दें कि स्केल को यह स्वीकार करने के लिए कि पथ-निर्भर प्रकार समान हैं, एकत्रीकरण के लिए अक्सर आपको सिंगलटन-प्रकार जैसे सिंगल (: UserModule.type) निर्दिष्ट करने की आवश्यकता होती है। लक्षणों को मिलाकर एक और शक्ति यह है कि यह रिकर्सिव निर्भरताओं को संभाल सकता है - UserModule और CustomerModule दोनों एक दूसरे से कुछ प्रदान करने और आवश्यकता के लिए कुछ प्रदान कर सकते हैं। यह आलसी vals का उपयोग करके एकत्रीकरण के साथ भी संभव है, लेकिन यह मिश्रण गुणों के साथ अधिक वाक्य रचनात्मक रूप से सुविधाजनक है।

+0

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

+0

महान स्पष्टीकरण और उदाहरणों के लिए धन्यवाद, यह अब बहुत स्पष्ट है। सिंगलटन-प्रकार और रिकर्सिव निर्भरताएं भी मुझे सामने आईं, इसलिए इससे भी मदद मिली। मिश्रित विशेषता दृष्टिकोण के साथ मुझे परेशान करता है कि मॉड्यूल में सभी मिश्रित निर्भरताओं की वजह से जल्दी से भंडार/सेवाओं/जो भी हो, का पूरा समूह होता है, इसलिए जब आप एक मॉड्यूल का उपयोग करते हैं तो आप उन सभी "संपार्श्विक" तक पहुंच प्राप्त करते हैं। कक्षाएं हालांकि आपको जरूरी नहीं है/चाहते हैं। – user1498572

4

मेरी हाल ही में प्रकाशित Slick architecture cheat sheet देखें। यह डेटाबेस चालक पर सार नहीं है, लेकिन यह मामूली है कि इसे इस तरह से बदल दें। बस

class Profile(profile: JdbcProfile){ 
    import profile.simple._ 
    lazy val db = ... 
    // <- cheat sheet code here 
} 

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

यदि डेटाबेस तालिका प्रति बार बार-बार सिंटैक्स ओवरहेड आपको परेशान करता है, तो कोड उत्पन्न करें। Slick code-generator is customizable बिल्कुल उस उद्देश्य के लिए:

यदि आप हाथ से लिखे गए और जेनरेट कोड को मिश्रित करना चाहते हैं, तो कोड-जनरेटर में हाथ से लिखित कोड फ़ीड करें या एक योजना का उपयोग करें, जहां जेनरेट कोड हाथ से लिखित कोर से प्राप्त होता है विपरीत क्रम में।

किसी और चीज से स्लिम को बदलने के लिए, किसी अन्य लाइब्रेरी का उपयोग करके क्वेरी के साथ डीएओ विधियों को प्रतिस्थापित करें।

+0

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

+0

हां, हमें स्लिम कोड जेन के बॉक्स एकीकरण और प्ले (या स्लिम) के विकास को प्रदान करने और बाहर करने की आवश्यकता है। यहां इस दिशा में काम किया गया है: http://blog.papauschek.com/2013/12/play-framework-evolutions-slick-2-0-code-generator/ – cvogt

+0

हाँ मैंने इसे देखा है यह आशाजनक लग रहा है। मैं शायद स्थिर होने पर इसका उपयोग कर दूंगा और ऐप बहुत बड़ा हो जाएगा, लेकिन अब मेरे लिए मॉडल कक्षाओं की संख्या इतनी बड़ी नहीं है और इसे मैन्युअल रूप से प्रबंधित किया जा सकता है, और इससे मुझे यह समझने में मदद मिलती है कि मैं क्या कर रहा हूं:) – user1498572

संबंधित मुद्दे