2012-02-23 30 views
5

क्या स्केल के प्रकार-सिस्टम का उपयोग करने के लिए एक पूर्ण ऑब्जेक्ट ग्राफ़ के संदर्भ-प्रासंगिक सबग्राफ को संक्षेप में निर्दिष्ट करने का कोई तरीका है?स्कैला किसी ऑब्जेक्ट ग्राफ़ को बाधित कर सकता है ताकि संदर्भ के लिए प्रासंगिक केवल वे वस्तुएं दिखाई दे सकें?

डीसीआई का तर्क है कि आपके पास अक्सर एक जटिल जटिल ग्राफ ग्राफ होता है लेकिन किसी भी एक प्रयोग-मामले में आप अक्सर उप-ग्राफ के साथ काम करना चाहते हैं। आपके पास Foo है जिसमें Bar और Bat है, लेकिन जब आप उपयोग-मामले 1 में हैं, तो आप केवल Bar पर ध्यान देते हैं और जब उपयोग-मामले 2 में, केवल Bat के बारे में।

उदाहरण के लिए, मान लीजिए कि आप इस संरचना है, और Role1 यूज-केस Foo->Bar->Baz->Bin की आवश्यकता है और Role2 का उपयोग-केस Foo->Bat->Baz->Buz की आवश्यकता है:

class Foo{ 
    val bar = new Bar() //Only relevant to Role 1 
    val bat = new Bat() //Only relevant to Role 2 
} 

class Bar { 
    val baz = new Baz() 
} 

class Bat { 
    val baz = new Baz() 
} 

//Relevant to both Role 1 and 2 (via Bar or Bat) 
class Baz { 
    val bin = new Bin() //Only relevant to Role 1 
    val buz = new Buz() //Only relevant to Role 2 
} 

class Bin{} 
class Buz{} 

यह देखना चाहते हैं कि आप एक में पहुँच विवश कर सकते हैं आसान है एकल वर्ग लक्षण का उपयोग करके:

trait FooInRole1 { def bar : Bar } //Define accessor in trait 
s/Foo/Foo extends FooInRole1/  //Change Foo's declaration to implement trait 
val f : FooInRole1 = new Foo  //LHS is i'face, RHS is implementation 
//f.bat <--Compile error    Irrelevant field is not available. \o/ 

लेकिन आप हर के लिए इस पद्धति को दोहराना use- के लिए प्रासंगिक आपत्ति मामला। (उदाहरण के लिए, आप bin पहुँचने के लिए एक BazInRole1 की जरूरत है और एक BazInRole2biz तक पहुँचने के लिए)

मेरा प्रश्न किसी तरह इन सभी आसानी से मिल-गलत, नाम स्थान-भीड़ लक्षण लेखन से बचने के लिए है कि क्या वहाँ है। उदाहरण के लिए, मैं इस कोड की तरह कुछ कल्पना कर सकता है (जो संकलन नहीं करता है):

class Foo[T] { 
    T match { 
    case r1 : Role1 => def bar : Bar[T] 
    case r2 : Role2 => def bat : Bat[T] 
    case _ => //Nothing 
    } 
} 

val fInRole1 = new Foo[Role1] //Provides Foo->Bar->Baz->Bin 
val fInRole2 = new Foo[Role2] //Provides Foo->Bat->Baz->Buz 

यह स्काला के प्रकार प्रणाली की तरह लगता है काफी अर्थपूर्ण इस तरह कुछ करने के लिए है, लेकिन मैं इसे समझ नहीं कर सकते हैं।

+0

मुझे लगता है कि इस प्रकार कुछ प्रकार के वर्गों के साथ हासिल किया जा सकता है। ऑब्जेक्ट ग्राफ़ पर टाइप-क्लास को दृश्य बनाएं और केवल टाइप-क्लास के माध्यम से इसकी सामग्री को एक्सेस करें और उसका उपयोग करें। – ziggystar

उत्तर

0

अगर मैं आपके सवाल का सही ढंग से समझ में आ (जो मैं के बारे में सुनिश्चित नहीं कर रहा हूँ) आप Foo चाहते या तो bar या batFoo के प्रकार के पैरामीटर के आधार पर में से एक प्रदान करने के लिए।

मेरा पहला शॉट होगा:

class Bar 
class Bat 

trait BarExt { def bar = new Bar } 
trait BatExt { def bat = new Bat } 

trait Role 
case object Role1 extends Role 
case object Role2 extends Role 

trait RoleProvider[From <: Role, To] { 
    def apply(): To 
} 

object RoleProvider { 
    implicit val r1 = new RoleProvider[Role1.type, Foo[Role1.type] with BarExt] { 
    def apply() = new Foo[Role1.type] with BarExt 
    } 

    implicit val r2 = new RoleProvider[Role2.type, Foo[Role2.type] with BatExt] { 
    def apply() = new Foo[Role2.type] with BatExt 
    } 
} 

class Foo[T <: Role] 

object Foo { 
    def create[T <: Role, To](f: T)(implicit rp: RoleProvider[T,To]): To = rp() 
} 
तो

कि

scala> Foo.create(Role1) 
res1: Foo[Role1.type] with BarExt = [email protected] scala> Foo.create(Role1).bar 

scala> Foo.create(Role1).bar 
res2: Bar = [email protected] 

scala> Foo.create(Role1).bat 
<console>:12: error: value bat is not a member of Foo[Role1.type] with BarExt 
       Foo.create(Role1).bat 

और

scala> Foo.create(Role2).bat 
res3: Bat = [email protected] 

scala> Foo.create(Role2).bar 
<console>:12: error: value bar is not a member of Foo[Role2.type] with BatExt 
       Foo.create(Role2).bar 

एक परिभाषाओं में इसी घोषणाओं खींच कर BarExt और BatExt से छुटकारा पाने सकता है r1 औरका, हालांकि मैं इसे "कठिन" उस के साथ काम करने के लिए लगता है:

implicit val r1 = new RoleProvider[Role1.type, Foo[Role1.type] { val bar: Bar }] { 
    def apply() = new Foo[Role1.type] { val bar = new Bar } 
} 

implicit val r2 = new RoleProvider[Role2.type, Foo[Role2.type] { val bat: Bat }] { 
    def apply() = new Foo[Role2.type] { val bat = new Bat } 
} 

लब्बोलुआब यह है, मैं अभी भी यकीन नहीं कर रहा हूँ कि इस वास्तव में आप जो चाह रहा है, या यह क्या है?

+0

मुझे नहीं लगता कि यह वही है जो मैं ढूंढ रहा हूं। बाज़ के बारे में सोचें (या, बदतर, क्रॉस-रेफरेंस के साथ 20 कक्षाओं का ग्राफ)। यह सुनिश्चित करने के लिए कि Baz.bin केवल रोल 1 में उपलब्ध है, क्या मुझे प्रति ऑब्जेक्ट प्रति ऑब्जेक्ट (xExt) परिभाषित नहीं करना है और प्रति किनारे एक रूपांतरण एफएन लिखना है? शायद यह सबसे अच्छा है जो किया जा सकता है, लेकिन मैं * उम्मीद कर रहा था * फू से बाज तक टाइप-पैरामीटर को "कैस्केड" करने का तरीका ढूंढने के लिए। क्या इसका कोई मतलब है? –

+0

तो * सभी * विधियों को मूल ग्राफ में निहित किया जाना चाहिए, लेकिन जब किसी निश्चित भूमिका से ग्राफ को "देखना" होता है, तो केवल उन विधियों का एक उप-समूह उजागर होता है? मुझे लगता है कि "सबग्राफ" से आप नोड्स के एक ही सेट का जिक्र कर रहे हैं लेकिन अलग-अलग, प्रकार-निर्भर भूमिकाओं के साथ? – fotNelton

+0

हां, यही वही है जो मैं उम्मीद कर रहा हूं। –

0

डीसीआई पर this artima article में, लेखक स्कैला में डीसीआई आर्किटेक्चर प्राप्त करने का एक तरीका प्रस्तुत करता है, जो कि आप किस चीज के लिए लक्षित हैं।

मूल विचार यह है कि आपके उपयोग-मामले के लिए प्रासंगिक तरीकों को परिभाषित करना एक विशेषता है, लेकिन आपके दृष्टिकोण के बजाय यह एक निश्चित आधार वर्ग का उद्देश्य सुनिश्चित करने के लिए एक स्व-प्रकार एनोटेशन का उपयोग करता है।

तो इसे थोड़ा और अधिक पहुंचने योग्य बनाने के लिए: आपके पास डेटा-क्लास Data है, जिसमें आपके डेटा ऑब्जेक्ट्स के प्राथमिक घटक शामिल हैं। आप एक निश्चित यूज-केस, जो एक निश्चित भूमिका में एक Data वस्तु पर विचार करने के लिए पसंद करती है एहसास करना चाहते हैं Role आप इस तरह की भूमिका तैयार कर सकते हैं:

trait Role { self : Data => 
    def methodForOnlyThisUseCase = {...} 
} 

यूज-केस के निष्पादन के लिए, आप तो एक बनाने के माध्यम से इस भूमिका के लिए विशिष्ट वस्तु:

val myUseCaseObject = new Data with Role 

इस तरह, वस्तु myUseCaseObject वास्तव में अपने Data घटकों और तरीकों को देखते हुए यूज-केस में अपनी भूमिका के लिए आवश्यक तक सीमित है।

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

+0

हां, यह डीसीआई के बारे में एक महत्वपूर्ण लेख है, और मेरा प्रश्न इस प्रकार के डिज़ाइन से शुरू होता है, लेकिन मुद्दा यह है कि आपको प्रत्येक कक्षा-भूमिका में स्पष्ट रूप से एक विशेषता लिखनी है। मेरे उदाहरण में, आप एक विशेषता FooInRole1, FooInRole2 और BazInRole1, BazInRole2 बनाने के लिए समाप्त होते हैं, और आप रोल प्रकार को "बाज़" से गुजरने के लिए BarInRole1 बनाने के लिए भी समाप्त होते हैं। यह * हो सकता है कि यह उतना अच्छा है जितना आप कर सकते हैं, लेकिन ऐसा लगता है कि इतना नामस्थान अव्यवस्था से बचने का एक तरीका होना चाहिए। –

1

बेहद संक्षिप्त नहीं है, और सदस्य वहां हैं, उपयोग करना असंभव है, लेकिन शायद इस दिशा में जाकर स्वीकार्य होगा?

class Foo[R] { 
    def bar(implicit ev: R <:< Role1) = new Bar[R] //Only relevant to Role 1 
    def bat(implicit ev: R <:< Role2) = new Bat[R] //Only relevant to Role 2 
}