स्वच्छ वास्तुकला एक उपयोग के मामले प्रस्तोता (जो इंजेक्ट किया जाता है DIP निम्नलिखित,) के वास्तविक क्रियान्वयन फोन interactor प्रतिक्रिया / प्रदर्शन को संभालने के लिए जाने के लिए पता चलता है। हालाँकि, मैं देख रहा हूँ कि लोग इस आर्किटेक्चर को कार्यान्वित कर रहे हैं, इंटरेक्टर से आउटपुट डेटा लौटा रहे हैं, और फिर कंट्रोलर (एडॉप्टर लेयर) को यह तय करने दें कि इसे कैसे संभालना है। दूसरा समाधान अनुप्रयोग परत से अनुप्रयोग जिम्मेदारियों को लीक करना है, इसके अलावा अंतःक्रियात्मक को इनपुट और आउटपुट पोर्ट को स्पष्ट रूप से परिभाषित नहीं करने के अलावा?
इनपुट और आउटपुट पोर्ट
क्लीन आर्किटेक्चर परिभाषा को ध्यान में रखते हुए , और विशेष रूप से कंट्रोलर, उपयोग केस इंटरेक्टर और प्रस्तुतकर्ता के बीच संबंधों का वर्णन करते हुए थोड़ा प्रवाह आरेख, मुझे यकीन नहीं है कि अगर मुझे सही से समझ में आ जाए कि "यूज़ केस आउटपुट पोर्ट" क्या होना चाहिए।
हेक्सागोनल वास्तुकला की तरह स्वच्छ वास्तुकला, प्राथमिक बंदरगाहों (तरीकों) और माध्यमिक बंदरगाहों (एडेप्टर द्वारा लागू किए जाने वाले इंटरफेस) के बीच अंतर करता है। संचार प्रवाह के बाद, मुझे उम्मीद है कि "केस केस इनपुट पोर्ट का उपयोग करें" एक प्राथमिक पोर्ट (इस प्रकार, बस एक विधि), और "केस केस आउटपुट पोर्ट का उपयोग करें" को लागू करने के लिए एक इंटरफ़ेस, शायद एक वास्तविक निर्माता को लेने वाला तर्क है, ताकि इंटरएक्टर इसका इस्तेमाल कर सके।
कोड उदाहरण
एक कोड उदाहरण बनाने के लिए, यह नियंत्रक कोड हो सकता है:
Presenter presenter = new Presenter();
Repository repository = new Repository();
UseCase useCase = new UseCase(presenter, repository);
useCase->doSomething();
प्रस्तुतकर्ता इंटरफ़ेस:
// Use Case Output Port
interface Presenter
{
public void present(Data data);
}
अंत में, अपने आप से बातचीत करने वाला:
class UseCase
{
private Repository repository;
private Presenter presenter;
public UseCase(Repository repository, Presenter presenter)
{
this.repository = repository;
this.presenter = presenter;
}
// Use Case Input Port
public void doSomething()
{
Data data = this.repository.getData();
this.presenter.present(data);
}
}
प्रस्तोता को फोन करने वाले पर
पिछली व्याख्या की पुष्टि उक्त आरेख से ही होती है, जहां नियंत्रक और इनपुट पोर्ट के बीच के संबंध को "तीक्ष्ण" सिर ("एसोसिएशन" के लिए यूएमएल) के साथ एक ठोस तीर द्वारा दर्शाया गया है, जिसका अर्थ है ",", जहां नियंत्रक "में" उपयोग मामला है), जबकि प्रस्तुतकर्ता और आउटपुट पोर्ट के बीच का संबंध एक ठोस तीर द्वारा "सफेद" सिर ("विरासत" के लिए यूएमएल) द्वारा दर्शाया गया है, जो "कार्यान्वयन" के लिए एक नहीं है, लेकिन शायद वैसे भी इसका मतलब है)।
इसके अलावा, एक अन्य प्रश्न के उत्तर में , रॉबर्ट मार्टिन ने वास्तव में एक उपयोग के मामले का वर्णन किया है जहां इंटरैक्टर प्रस्तुतकर्ता को पढ़ने के अनुरोध पर कहता है:
मानचित्र पर क्लिक करने से या तो प्लेसपिनकंट्रोलर को आमंत्रित किया जाता है। यह क्लिक के स्थान को इकट्ठा करता है, और किसी भी अन्य प्रासंगिक डेटा को बनाता है, एक प्लेसप्रिनिस्टर डेटा संरचना का निर्माण करता है और इसे प्लेसपिनइंटरएक्टर के पास भेज देता है जो पिन के स्थान की जांच करता है, यदि आवश्यक हो, तो पिन रिकॉर्ड करने के लिए एक प्लेस इकाई बनाएं, एक EditPlaceReponse का निर्माण करता है ऑब्जेक्ट और इसे EditPlacePresenter में पास करता है जो स्थान संपादक स्क्रीन को लाता है।
एमवीसी के साथ इस खेल को अच्छी तरह से बनाने के लिए, मैं सोच सकता था कि पारंपरिक रूप से नियंत्रक में जाने वाले आवेदन तर्क को यहां इंटरएक्टर में स्थानांतरित कर दिया जाएगा, क्योंकि हम नहीं चाहते कि कोई भी एप्लिकेशन तर्क एप्लिकेशन परत के बाहर लीक हो। एडेप्टर लेयर में कंट्रोलर सिर्फ इंटरेक्टर को कॉल करेगा, और हो सकता है कि प्रक्रिया में कुछ मामूली डेटा फॉर्मेट रूपांतरण करें:
इस लेयर का सॉफ्टवेयर एडेप्टरों का एक समूह है जो डेटा को उपयोग के मामलों और संस्थाओं के लिए सबसे सुविधाजनक प्रारूप से परिवर्तित करता है, किसी बाहरी एजेंसी जैसे डेटाबेस या वेब के लिए सबसे सुविधाजनक प्रारूप में।
मूल लेख से, इंटरफ़ेस एडेप्टर के बारे में बात करना।
इंटरेक्टर रिटर्निंग डेटा पर
हालांकि, इस दृष्टिकोण के साथ मेरी समस्या यह है कि उपयोग के मामले को प्रस्तुतिकरण का ध्यान रखना चाहिए। अब, मैं देख रहा हूं कि Presenter
इंटरफ़ेस का उद्देश्य कई अलग-अलग प्रकार के प्रस्तुतकर्ता (GUI, Web, CLI, आदि) का प्रतिनिधित्व करने के लिए पर्याप्त सार है, और यह वास्तव में "आउटपुट" का अर्थ है, जो एक उपयोग मामला हो सकता है बहुत अच्छा है, लेकिन फिर भी मैं इसके साथ पूरी तरह से आश्वस्त नहीं हूं।
अब, साफ वास्तुकला के अनुप्रयोगों के लिए वेब के चारों ओर देख रहा हूं, मुझे लगता है कि लोग केवल कुछ डीटीओ को लौटाने वाली विधि के रूप में आउटपुट पोर्ट की व्याख्या कर रहे हैं। यह कुछ इस तरह होगा:
Repository repository = new Repository();
UseCase useCase = new UseCase(repository);
Data data = useCase.getData();
Presenter presenter = new Presenter();
presenter.present(data);
// I'm omitting the changes to the classes, which are fairly obvious
यह आकर्षक है क्योंकि हम उपयोग के मामले में प्रस्तुति को "कॉल" करने की ज़िम्मेदारी से आगे बढ़ रहे हैं, इसलिए उपयोग मामला केवल डेटा प्रदान करने के साथ ही क्या करना है, यह जानने की चिंता नहीं करता है। इसके अलावा, इस मामले में हम अभी भी निर्भरता नियम नहीं तोड़ रहे हैं, क्योंकि उपयोग के मामले में अभी भी बाहरी परत के बारे में कुछ भी नहीं पता है।
हालांकि, उपयोग का मामला उस क्षण को नियंत्रित नहीं करता है जब वास्तविक प्रस्तुति अब की जाती है (जो उपयोगी हो सकती है, उदाहरण के लिए उस बिंदु पर अतिरिक्त सामान करने के लिए, जैसे लॉगिंग, या यदि आवश्यक हो तो इसे पूरी तरह से समाप्त करना)। इसके अलावा, ध्यान दें कि हमने उपयोग केस इनपुट पोर्ट को खो दिया है, क्योंकि अब नियंत्रक केवल getData()
विधि का उपयोग कर रहा है (जो हमारा नया आउटपुट पोर्ट है)। इसके अलावा, यह मुझे दिखता है कि हम "बताएं, मत पूछो" सिद्धांत को यहां तोड़ रहे हैं, क्योंकि हम कुछ डेटा के लिए इंटरैक्टर को इसके साथ कुछ करने के लिए कह रहे हैं, बजाय इसके कि यह वास्तविक चीज़ करने के लिए कहे। पहले स्थान पर।
मुद्दे पर
तो, इन दोनों विकल्पों में से कोई भी क्लीन आर्किटेक्चर के अनुसार उपयोग केस आउटपुट पोर्ट की "सही" व्याख्या है? क्या वे दोनों व्यवहार्य हैं?