2013-04-06 12 views
5

में अनुरोध संदर्भ पासिंग परोक्ष मैं सहयोग अभिनेताओं में से एक प्रणाली में परोक्ष एक अनुरोध संदर्भ का प्रचार करना चाहते हैं।एक अभिनेता प्रणाली

को सरल बनाने और स्थिति को पेश करने के लिए, अपने सिस्टम कई अभिनेताओं और संदेशों इन अभिनेताओं को पारित कर दिया है इस RequestContext वस्तु को शामिल करने की जरूरत है।

ActorA प्रकार MessageA का संदेश प्राप्त करता ActorB प्रकार MessageB के संदेशों

जब ActorA MessageA की हैंडलिंग के भाग के रूप, ActorB के लिए एक संदेश भेजने के लिए की जरूरत है, यह व्यापार तर्क करता है, और फिर से एक MessageB निर्माण करती प्राप्त करता है तर्क के साथ-साथ MessageA में RequestContext उपलब्ध के परिणामों और फिर इसे ActorB को

def handle(ma:MessageA) { 
val intermediateResult = businessLogic(ma) 
actorB ! MessageB(intermediateResult, ma.requestContext) 
} 

भेजता हम संदेशों के एक धसान नियंत्रित किया जाना है, और स्पष्ट रूप से requestContext आसपास गुजर बोझिल है।

मैं स्काला के implicits उपयोग करने के लिए रचनात्मक तरीके की कोशिश कर रहा हूँ स्पष्ट रूप से RequestContext बाहर जाने वाले संदेश में भेजे संदेश में एम्बेडेड इंजेक्शन लगाने से बचने के लिए शामिल हैं।

संदेशों मामले वर्ग हैं (और वे होने की जरूरत है)। मैंने निहितार्थ नियमों के बारे में पढ़ा है लेकिन वर्तमान वस्तु के दायरे में किसी ऑब्जेक्ट की विशेषता लाने से दूर-दराज लगती है।

यह, मुझे यकीन है कि एक आम आवश्यकता होना चाहिए हूँ। कोई सुझाव?

धन्यवाद।

उत्तर

6

मेरी राय में, सबसे आसान तरीका है अपने वैल मामले वर्ग में निहित बनाना है।

case class MessageA(req: RequestA)(implicit val ctx: RequestContext) 

case class MessageB(req: RequestB)(implicit val ctx: RequestContext) 

def businessLogic(req:RequestA):RequestB 


def handle(ma: MessageA): Unit = { 
    // import all the members of ma so that there is a legal implicit RequestContext in scope 
    import ma._ 
    val intermediateResult = businessLogic(req) 
    actorB ! MessageB(intermediateResult) 
} 
+0

उत्तर के लिए धन्यवाद। मैंने गंभीरता से इस दृष्टिकोण को माना, लेकिन मैंने यह सोचा कि पैरामीटर को पारित करने से सुविधा का उपयोग करने के लिए सभी आयात और implicits जोड़ने से कहीं अधिक पठनीय और कम वर्बोज़ है - क्या आपको नहीं लगता? – vishr

+0

यदि यह कोई समस्या है, तो मैं एक संदेश प्रोसेसर को कारक बनाउंगा, जो एक संदेश ए => संदेश बी है और इसे अभिनेता के शरीर में बस कॉल करें। यह टेस्टेबिलिटी भी बढ़ाएगा – Edmondo1984

6

अपने उदाहरण सवाल में संदेश के अपने हैंडलिंग पहले से ही एक विधि में बाहर शामिल होती है, जो इस सीधी-सपाट बनाता में:

trait RequestContext 

case class MessageA(req: RequestA, ctx: RequestContext) 
object MessageA { 
    def apply(req: RequestA)(implicit ctx: RequestContext) = MessageA(req, ctx) 
} 

case class MessageB(req: RequestB, ctx: RequestContext) 
object MessageB { 
    def apply(req: RequestB)(implicit ctx: RequestContext) = MessageB(req, ctx) 
} 

class Example extends Actor { 

    def receive = { 
    case MessageA(req, ctx) => handle(req)(ctx) 
    } 

    def handle(req: RequestA)(implicit ctx: RequestContext): Unit = { 
    val intermediateResult = businessLogic(req) // could take implicit ctx as well 
    actorB ! MessageB(intermediateResult) 
    } 
} 

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

के एक बदलाव के ऊपर हो सकता है:

case class MessageA(req: RequestA, ctx: RequestContext) 
object MessageA { 
    def apply(req: RequestA)(implicit ctx: RequestContext) = MessageA(req, ctx) 
    implicit def toContext(implicit msg: MessageA) = msg.ctx 
} 

case class MessageB(req: RequestB, ctx: RequestContext) 
object MessageB { 
    def apply(req: RequestB)(implicit ctx: RequestContext) = MessageB(req, ctx) 
    implicit def toContext(implicit msg: MessageB) = msg.ctx 
} 

... 
def handle(implicit ma: MessageA): Unit = { 
    val intermediateResult = businessLogic(req) 
    actorB ! MessageB(intermediateResult) 
} 
+0

क्यों एक निहित संदेश? अनुरोध नहीं है जो अंतर्निहित होना चाहिए? मेरा उत्तर – Edmondo1984

+0

@ रोलैंड देखें, आपके विचार ने एक स्वच्छ दृष्टिकोण को प्रेरित किया। यदि MessageA और MessageB सार मैसेज से प्राप्त होता है, और हम सार मैसेज से सार मैसेज के सहयोगी ऑब्जेक्ट के भीतर RequestContext में एक अंतर्निहित रूपांतरण प्रदान करते हैं, तो समस्या हल हो जाती है! प्रत्येक संदेश को जो कुछ करने की ज़रूरत है वह एक निहित अनुरोध संदर्भ पैराम घोषित करता है, और साथ ही साथ उपलब्ध है, यह साथ ही पारित किया जाएगा! – vishr

+0

खैर ... मैं उत्साहित हो गया ... यह पता चला है कि काम करने के लिए अंतर्निहित MessageA पैरामीटर के साथ प्रत्येक हैंडल विधि को चिह्नित करना आवश्यक है, लेकिन इसे पठनीय नहीं बनाता है। अंतर्निहित घोषणा व्यापार तर्क कोड पर बहुत अधिक प्रचार करती है। – vishr

0

मूल संदेश और संदर्भ दोनों को एक सामान्य लिफाफा वर्ग बनाएं। एक विशेषता Actor विस्तार (आप akka._ पैकेज में यह जगह करने के लिए है) बनाएँ। ओवरराइड विधि aroundReceive() जो आपके लिफाफे को अनपैक करता है, वर्तमान संदर्भ को संग्रहीत करने के लिए एक अभिनेता के संरक्षित चर को प्रारंभ करता है, अनपॅक किए गए संदेश के साथ मूल प्राप्त विधि को कॉल करता है, संदर्भ चर को अनियंत्रित करता है। बल्कि एक संदिग्ध दृष्टिकोण है, लेकिन यह वास्तव में Actor.sender() व्यवहार करता है।

ऐसे संदर्भित अभिनेता को संदेश भेजने के लिए, आपको अपना संदेश मैन्युअल रूप से ऊपर दिए गए लिफाफा में लपेटना होगा, या आप इस कार्य को स्वचालित रूप से ActorRef पर विस्तारित करके स्वचालित कर सकते हैं जो लागू/पूछताछ ऑपरेशन द्वारा लागू करता है संदेश को संदर्भित करने के लिए उठा रहा है।

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

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