2012-03-21 10 views
10

मैं एक साधारण उपयोग के मामले के लिए ऑब्जेक्ट उन्मुख डिजाइन का मूल अभ्यास कर रहा हूं: एक पुस्तक को कई टैग के साथ टैग किया जा सकता है।किताबों और टैगों के ओओ डिजाइन

मेरे पास कई समाधान हैं, और मैं आपका इनपुट चाहता हूं जिस पर ओओडी सिद्धांतों और रखरखाव की अवधि में बेहतर है।

विकल्प 1

public class Book { 
    private String title; 
    //... other attributes 

    private List<Tag> tags; 
} 

बात यह है कि परेशान मुझे हम अतिरिक्त वर्गीकरण या खोज डेटा के साथ एक पुस्तक के मूल गुण मिलाया है। मुझे भविष्य में एक आवश्यकता हो सकती है जहां कुछ पुस्तकों को टैग नहीं किया जा सकता है। भविष्य में, बुक वर्ग फूला हुआ बन सकता है जब मैं और अधिक responsabilities जोड़ें: श्रेणी, उन है कि यह पढ़ा है, रेटिंग की सूची ...

विकल्प 2

public class TaggedBook extends Book { 
    private Book book; 

    private List<Tag> tags; 
} 

मुझे लगता है कि इस के समान है सजावटी पैटर्न, लेकिन मुझे यह यहां फिट नहीं दिख रहा है क्योंकि मैं व्यवहार का विस्तार नहीं कर रहा हूं।

विकल्प 3

दसगुणा पुस्तकें और टैग comnpletely, और एक पुस्तक से टैग को पुनः प्राप्त करने के लिए एक सेवा का उपयोग (प्रत्येक पुस्तक दी एक अद्वितीय पहचानकर्ता है)

List<Tag> TagService.getTags(Book book) 

हालांकि, मुझे नहीं पता इस समाधान को बहुत ही सुरुचिपूर्ण लगता है (है ना?), और मुझे दो प्रश्न भेजना पड़ सकता है: एक पुस्तक को पुनः प्राप्त करने के लिए, दूसरा टैग के लिए।

मैं अन्य आवश्यकताओं के लिए सबसे अच्छा विकल्प को लागू करने पर योजना बना रहा हूँ: एक पुस्तक रेटिंग है, एक पुस्तक वर्गीकृत किया जा सकता ...

मैं भी किताबें और टैग वस्तुओं स्टोर करने के लिए एक डीएमएस के प्रयोग पर योजना बना रहा हूँ। चूंकि यह संबंध डेटाबेस नहीं है, इसकी स्कीमा क्लास डिज़ाइन से मेल खाती है।

धन्यवाद

+0

क्या "टैग" स्वयं की इकाई नहीं होगी? , के रूप में सिर्फ एक स्ट्रिंग की तुलना में अधिक है - यह एक वर्णन है और इस तरह ... – cHao

+0

हाँ धन्यवाद हो सकता था, यह मेरा मूल डिजाइन था, लेकिन मैं जिस तरह से सवाल –

उत्तर

1

मैं उन्हें पूरी तरह से अलग करने के लिए तीसरा विकल्प पसंद करता हूं।

पुस्तकें और टैगों में उन्हें अलग करके एक बहुत से संबंध हैं, आप "कंप्यूटर साइंस" द्वारा कौन सी पुस्तकें टैग की गईं "जैसे प्रश्न बनाने में आसान बना सकते हैं।

+0

में शामिल करना भूल गया, जिसे "टैग" भी है एक इकाई, है ना? –

+0

हाँ, यह है। मैंने अपने प्रश्न –

4

यदि पुस्तकें आपके मॉडल में एकमात्र इकाई नहीं हैं जिन्हें टैग किया जा सकता है। मैं इस इंटरफेस के साथ जाना होगा:

public interface Taggeable { 
    public List<Tag> getTags();   
    public void setTags (List<Tag> tags) 
} 

और

public class Book implements Taggeable { 
//Book attributes and methods 

पुस्तकें के प्रकार/संस्थाओं है कि टैग की गईं जा सकती है, केवल इस इंटरफ़ेस को लागू करने की जरूरत है। इस तरह, आपके पास पुस्तक ऑब्जेक्ट्स हो सकती हैं जो टैगिंग और अन्य को अनुमति देती हैं जो नहीं करती हैं। साथ ही, टैगिंग तंत्र का उपयोग आपके मॉडल के अन्य ऑब्जेक्ट्स के साथ किया जा सकता है।

5

सभी तीन विकल्प आपके क्लास डिज़ाइन के लिए मान्य और अच्छे विकल्प हो सकते हैं। यह सब पूर्ण संदर्भ/आवश्यकताओं पर निर्भर करता है। आपके द्वारा सूचीबद्ध आवश्यकता "दाएं" निर्णय लेने के लिए पर्याप्त नहीं है।उदाहरण के लिए, यदि आपका आवेदन पुस्तक केंद्रित है और टैग को किताबों से स्वतंत्र रूप से विकसित या लिखने की आवश्यकता नहीं है, तो विकल्प 3 शायद अनावश्यक जटिलता पेश करेगा। यदि आप एक सार्वजनिक एपीआई डिज़ाइन करते हैं जो आपके वास्तविक तर्क के चारों ओर एक मुखौटा के रूप में कार्य करता है तो भी आप विकल्प 1 या 2 के लिए जा सकते हैं, भले ही आंतरिक रूप से Book और Tag पूरी तरह से कुल जड़ें हैं। स्केलेबिलिटी, प्रदर्शन, एक्स्टेंसिबिली ... वे सभी संभावित आवश्यकताएं हैं जिन्हें आपको संतुलित करने की आवश्यकता है और यह आपके डिज़ाइन को प्रभावित करेगा।

यदि आप उद्यम अनुप्रयोगों के लिए कक्षा डिजाइन के लिए एक अच्छी औपचारिक पद्धति और मार्गदर्शन की तलाश में हैं, तो मैं आपको सुझाव दूंगा कि आप Domain Driven Design देखें।

इसके अलावा, अज्ञात भविष्य की आवश्यकताओं के लिए आपको कक्षाएं डिज़ाइन न करें। यह फिर भी बेकार जटिलता (सोच: लागत) जोड़ देगा। बस सुनिश्चित करें कि आपके पास पर्याप्त इकाई परीक्षण है जो आपकी आवश्यकताओं को वापस लेता है जब आपको नई आवश्यकताओं के लिए पुनर्विक्रेता की आवश्यकता होती है।

+0

को सही किया "इसके अलावा, अज्ञात भविष्य की आवश्यकताओं के लिए आपको कक्षाएं डिज़ाइन न करें।" यह, यह, यह! जब वह दिन आता है, रिफैक्टर। तब तक, इसे पहले से ही अधिक जटिल बनाना न करें। – GalacticCowboy

7

डेकोरेटर पैटर्न की अवधारणा अपने case.But में अच्छी तरह से फिट बैठता है मुझे लगता है कि strategy pattern अधिक उपयोगी और आपके में भी प्रभावी है case.If आप रणनीति पैटर्न के बारे में तो पता नहीं है This यह पर एक नजर डालें तो आप एक दे देंगे रणनीति पैटर्न पर अच्छा विचार। अगर आपको अधिक सुझाव की आवश्यकता है या कोई प्रश्न है तो टिप्पणी में पूछें। धन्यवाद सभी बेहतरीन ..

+0

रणनीति पैटर्न के लिंक के लिए हाय धन्यवाद, मैंने आज भी कुछ नया सीखा। लेकिन आप इस मामले में क्यों सोचते हैं कि यह सबसे अच्छा विकल्प होगा? – MrTJ

+0

@MrTJ: मुझे नहीं लगता कि यह सबसे अच्छा विकल्प होगा .. ऊपर दिए गए कोड का संदर्भ मुझे लगता है कि रणनीति पैटर्न अतिरिक्त वर्गीकरण, श्रेणियों, खोज डेटा, उपयोगकर्ताओं की सूची आदि के साथ भविष्य के विस्तार के लिए अपनी आवश्यकता को पूरा कर सकता है। –

2

मुझे लगता है कि बेहतर समाधान के लिए पैटर्न मिश्रण करना बेहतर होगा। याद रखें कि एक विशेष पैटर्न केवल एक विशेष समस्या हल करता है।

मेरा सुझाव अलग-अलग इंटरफेस को अलग करना और तदनुसार उनसे जुड़ना है। बेस क्लास में समर्थित इंटरफेस के लिए क्वेरी करने की क्षमता होनी चाहिए, ताकि वह उचित इंटरफ़ेस फ़ंक्शंस को कॉल कर सके।

public interface QueryInterface { 
    public boolean isTaggable(); 
    public boolean isRatable(); 
} 

अगले विशेष इंटरफेस आता है ...:

पहले इंटरफ़ेस क्वेरी समर्थित इंटरफेस है।

मान लीजिए पहले विशेष इंटरफ़ेस taggable है:

public interface Taggable { 
    public Vector<Tag> getTags(); 
    public boolean addTag(Tag newTag); 
} 

... और दूसरा एक करयोग्य है ...

public interface Rateable { 
    public Rating getRating(); 
    public void setRating(Rating newRating); 
} 

सादे पुराने आधार वर्ग में ही: :)

public class Book implements QueryInterface { 
    private String title; 
    public boolean isTaggable() { 
     return false; 
    } 

    public boolean isRateable() { 
     return false; 
    } 
} 

अब विशेष व्युत्पन्न वर्ग जो टैग करने योग्य इंटरफ़ेस का अनुपालन करता है:

public class TaggedBook extends Book implements Taggable { 
    private Vector<Tag> tags; 
    public Vector<Tag> getTags() { 
     return tags; 
    } 

    @override 
    public boolean isTaggable() { 
     return true; 
    } 

    public boolean addTag(Tag newTag) { 
     return tags.insert(newTag); 
    } 
} 

... और विभिन्न पुस्तक जो केवल करयोग्य है:

public class RatedBook extends Book implements Rateable { 
    private Rating rating; 
    public Rating getRating() { 
     return rating; 
    } 
    public void setRating(Rating newRating) { 
     this.rating = newRating; 
    } 

    @override 
    public boolean isRateable() { 
     return true; 
    } 
} 

आशा इस मदद करता है। :)

+0

धन्यवाद अलॉइस :) – fadedreamz

+0

पुस्तक के बारे में क्या है जिसे एक ही समय में टैग और रेट किया जा सकता है? टैगेड रेटेड या इसके विपरीत बढ़ाया जाना चाहिए? या वहां नई कक्षा होनी चाहिए जो टैग करने योग्य और रेट करने योग्य लागू करे? – Ivan

+0

नई कक्षा होनी चाहिए जो टैग करने योग्य और रेट करने योग्य लागू करे। – fadedreamz

2

विकल्प 1

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

आपके द्वारा दी गई दूसरी समस्या यह है कि भविष्य में आपके पास BookTag के बिना हो सकता है। चूंकि मुझे पूरी तस्वीर नहीं पता है, मैं केवल अनुमान लगा रहा हूं, लेकिन मैं दृढ़ता से तर्क दूंगा कि यह Book एस के साथ Book होगा।

विकल्प 3

मुझे लगता है कि यह काम करने के गैर OO तरीका है। कुछ आईडी के सहयोग से संबंधों को कार्यान्वित करना। मुझे यह बिल्कुल पसंद नहीं है।

प्रत्येक अतिरिक्त संपत्ति के लिए आप Book में जोड़ना चाहते हैं, तो आपको उचित Service प्रकार ऑब्जेक्ट भी बनाना होगा और विकल्प 1 पर ऐसा करने के लिए कोई लाभ नहीं होने के साथ बहुत सारे अतिरिक्त और अनावश्यक कॉल करना होगा।

एक और कारण यह है कि मुझे यह पसंद नहीं है कि इसका मतलब है कि Tag का किताबों के साथ संबंध है। मुझे नहीं लगता कि वे करते हैं।

विकल्प 2

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

मुझे लगता है कि आपका पहला समाधान सबसे अच्छा है। यदि आप कोड ब्लोट के बारे में चिंतित हैं तो आप ऑब्जेक्ट को Book के सदस्य के रूप में मान सकते हैं, जो स्वयं को खोजने के लिए ज़िम्मेदार है (यह एसओएलआईडी में एस के साथ भी मदद करता है) और Book के किसी भी अतिरिक्त गुण के लिए भी यही है। यदि Book में कोई टैग नहीं है तो Tags पूछे जाने पर झूठी वापसी करेगा, और Book उसको प्रतिबिंबित करेगा।

सारांश

इस तरह के एक साधारण सी समस्या के लिए, पर नहीं सोचता। ओओ डिजाइन के बुनियादी सिद्धांत (है-ए, आईएस-ए) सबसे महत्वपूर्ण हैं।

+0

+1 _do के लिए overthink_ नहीं। –

1

जब तक किसी पुस्तक के टैग या टैग पर टैग का क्रम दो बार एक ही टैग नहीं हो सकता है, तो आपको सूची के बजाय अपने टैग को सेट में स्टोर करना चाहिए।

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

2

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

तो, हमें यह तय करना होगा कि हमारे पास कौन सी कक्षाएं (संस्थाएं) हैं। Book एक वर्ग है क्योंकि समस्या का केंद्र है, इसमें अलग-अलग उदाहरण हैं और संभवतः, कई विशेषताओं और संचालन हैं। Tag एक मूल्य-वस्तु और एक वर्ग दोनों हो सकता है।

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

अब

, दूसरा विकल्प। Tag एक वर्ग भी हो सकता है क्योंकि यह किसी अन्य वर्ग (Book) से संबंधित है और इसके उदाहरण अलग-अलग हो सकते हैं। फिर हमारे पास दो वर्ग हैं: Book और Tag, और उनके बीच 'कई से कई' संगठन - TaggedWith। जैसा कि आप जानते हैं, एसोसिएशन एक रिश्ते के अलावा खुद ही एक वर्ग है। TaggedWith एसोसिएशन (लिंक) के उदाहरण Book और Tag के उदाहरण कनेक्ट करते हैं। इसके बाद हमें यह तय करना होगा कि Book और Tag के बीच पत्राचार के प्रबंधन के लिए कौन सी कक्षा जिम्मेदार होगी (बनाएं, पढ़ें, देखें, नष्ट करें, अपडेट करें ...)। यहां सबसे अधिक प्राकृतिक विकल्प इस जिम्मेदारी को TaggedWith एसोसिएशन को सौंपना है।

कुछ कोड लिखने की सुविधा देता है।

विकल्प 1

public class Book { 
    private Collection<String> tags; 

    /* methods to work with tags, e.g. */ 
    public void addTag(String tag) {...} 
    public String[] getAllTags() {...} 
    ... 

} 

यह जटिल है, लेकिन वास्तव में समान कोड सिर्फ माउस क्लिक के एक जोड़े में डिजाइन वर्णन से उत्पन्न किया जा सकता लग सकता है। दूसरी तरफ, यदि आप डीबी का उपयोग करते हैं तो यहां बहुत सारे कोड एसक्यूएल प्रश्न बन जाते हैं।

विकल्प 2

public class Tag { 
    /* we may wish to define a readable unique id for Tag instances */ 
    @Id 
    private String name; 

    /* if you need navigation from tags to books */ 
    private Collection<Book> taggedBooks; 
    public Collection<Book> getTaggedBooks() {...} 
    public void addBook(Book book) {...} // calls TaggedWith.create(this, book) 
    public void _addBook(Book book) {...} // adds book to taggedBooks 
    .... 
    /* I think you get the idea */ 


    /* methods to work with tags */ 
    public String getName() {...} 
    ... 

    /* Tags cannot be created without id (i.e. primary key...) */ 
    public Tag(String name) {...} 


    /* if you'd like to know all tags in the system, 
     you have to implement 'lookup' methods. 
     For this simple case, they may be put here. 
     We implement Factory Method and Singleton patterns here. 
     Also, change constructor visibility to private/protected. 
    */ 
    protected static HashMap<String, Tag> tags = ...; // you may wish to use a DB table instead 
    public static Tag getInstance(String name) {...} // this would transform to DAO for DB 
} 

public class Book { 
    /* if we need an id */ 
    @Id // made up 
    private String bookId; 

    /* constructors and lookup the same as for Tag 
     If you wish to use a database, consider introducing data access layer or use ORM 
    */ 

    /* if you need navigation from Book to Tag */ 
    private Collection<Tag> tags; 
    public Collection<Tag> getTags() {...} 
    ... 

} 

public TaggedWith { 
    /* constructor and lookup the same as for Tag and Book (!) */ 

    /* manage ends of the association */ 
    private Book book; 
    private Tag tag; 
    public Book getBook() {...} 
    public Tag getTag() {...} 

    protected TaggedWith(Book book, Tag tag) {  
      this.book = book; 
      this.tag = tag; 
      book._addTag(tag); // if you need navigation from books to tags 
      tag._addBook(book); // if you need navigation from tags to books 
    } 


    /* if you need to search tags by books and books by tags */ 
    private static Collection<TaggedWith> tagsBooks = ...; 
    public static TaggedWith create(Tag tag, Book book) { 
      // create new TaggedWith and add it to tagsBooks 
    } 
} 
1

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

public interface ITaggable 
{ 
    string Name { get; } 
} 

public class Book : ITaggable 
{ 
} 

public class Tag 
{ 
    private List<ITaggable> objects; 
    private String name; 

    public void AddObject() {} 
    public void RemoveObject() {} 
    public void HasObject() {} 
} 

public class TagManager 
{ 
    private List<Tag> tags; 

    private void InitFromDatabase() {} 
    public void GetTagsForObject(o: ITaggable) {} 
    public void GetObjectsForTag(objectName: String) {} // 
    public void GetObjectsForTag(t: Tag) {} // 
    public void GetObjectsForTag(tagName: String) {} // 
    public void GetAllTags(); 
} 

... somewhere else ... 

public void SearchForTag(tag: Tag) 
{ 
    TagManager tagManager = new TagManager(); 
    // Give me all tags with 
    List<ITaggable> books = tagManager.GetObjectsForTag("History"); 
} 
संबंधित मुद्दे