2015-10-10 7 views
7

मैं एक साधारण interface है कि मैं कुछ सुविधा के आधार पर Comparable होना चाहते है तो बोलो और एक अलग वर्ग के किसी भी दो उदाहरण में एक अलग जटिलता होगी। प्राकृतिक आदेश एक साथ कक्षाओं के सभी उदाहरणों को 'समूह' करेगा।को लागू इंटरफ़ेस तुलनाकारक

अब मैं एक वर्ग इसी क्रम में उदाहरणों के उस वर्ग के समूह के भीतर उस वर्ग के दो उदाहरण की तुलना के लिए विशेष रूप से डिफ़ॉल्ट तुलना ओवरराइड करता है में इस इंटरफ़ेस को लागू करना चाहते हैं।

class Bacteria implements Organism { 
    enum Shape {ROD, ROUND, SPIRAL}; 
    private final Shape shape; 

    @Override 
    public int compareTo(Organism other) { 
     if (other instanceof Bacteria) 
      return this.shape.compareTo((Bacteria)other.shape); 
     else 
      return Organism.super.compareTo(other); 
    } 
} 

मैं कोड के इस पैटर्न के साथ विशेष रूप से खुश नहीं हूँ: मैं निम्नलिखित पैटर्न का उपयोग एक बार इंटरफ़ेस को लागू करने वर्गों के सेट बड़ी यह काफी बनाए रखने के लिए जटिल हो जाता है हो जाता है और बार-बार कोड के बहुत सारे की आवश्यकता है और पर निर्भर करता है 'जटिलता' की एक अंतर्निहित संपत्ति। मैं आदेश को परिभाषित करने के Comparator शैली को पसंद करता हूं।

return Comparator 
    .comparingInt(Organism::getComplexity) 
    .thenComparing(Bacteria::getShape); 

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

+0

यह मुझे 'तुलनाकर्ता' [जिम्मेदारी की श्रृंखला] (https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern) जैसा लगता है। –

+1

नोट: आपके प्रकार की तुलना संक्रमणीय नहीं हो सकती है! मान लीजिए कि 'ए' जटिलता 1, आकार 2,' बी 'के साथ एक बैक्टीरिया है, जटिलता 2 के साथ एक गैर बैक्टीरिया जीव है, और 'सी' जटिलता 3, आकार 1 के साथ एक बैक्टीरिया है। ध्यान दें कि' a immibis

+0

मैं @immibis से सहमत हूं। मुझे लगता है कि चूंकि आप वैध तुलना को परिभाषित नहीं कर रहे हैं, इसलिए सवाल सार्थक नहीं है। – ajb

उत्तर

0

मुझे यकीन है कि तुम कहाँ Comparator डाल करने की योजना नहीं है। आप अपने वर्ग Comparable<Organism> लागू करना चाहते हैं के बाद से, मैं तुम्हें,

class Bacteria implements Organism { 
    enum Shape {ROD, ROUND, SPIRAL}; 
    private final Shape shape; 

    Comparator<Organism> comparator = 
     Comparator 
      .comparingInt(Organism::getComplexity) 
      .thenComparing(Bacteria::shape); // illegal 

    @Override 
    public int compareTo(Organism other) { 
     return comparator.compare(this, other); 
    } 
} 

यह काम नहीं करेगा की तरह कुछ के लिए देख रहे हैं क्योंकि thenComparing, संदर्भ में, एक पैरामीटर है कि एक Function कि संचालित है की जरूरत है मान लेंगे Organism पर, Bacteria पर नहीं। आपको इसके चारों ओर इस तरह काम कर सकता था - मैं तुम्हें करने के लिए इसे छोड़ तय करने के लिए यह पर्याप्त सुरुचिपूर्ण है:

Comparator<Organism> comparator = 
    Comparator 
     .comparingInt(Organism::getComplexity) 
     .thenComparing(x -> ((x instanceof Bacteria) ? ((Bacteria)x).getShape() : Shape.ROD)); 

सिद्धांत रूप में, आप भी अपनी खुद की विधि है कि एक और करने के लिए एक तुलनित्र में बदल सकते हैं लिख सकते हैं। आप instance.method संकेतन का उपयोग नहीं कर सकते, तो उपयोग के लिए होता है कुछ इस तरह होना करने के लिए:

Comparator<Organism> comparator = 
    MyComparatorUtilities.thenComparingIfInstanceOf(
     Comparator.comparingInt(Organism::getComplexity), 
     Bacteria.class, 
     Bacteria::getShape); 

thenComparingIfInstanceOf compiles (और कोड ऊपर संकलित करने के लिए अनुमति देता है) के निम्नलिखित कार्यान्वयन, लेकिन मैं परीक्षण करने के लिए प्रयास नहीं किया है यह:

class MyComparatorUtilities { 
    public static 
    <T,U extends T,V extends Comparable<? super V>> Comparator<T> thenComparingIfInstanceOf(
     Comparator<T> comparator, 
     Class<U> subclass, 
     Function<? super U, ? extends V> keyExtractor) { 
     return (a, b) -> { 
      int comp = comparator.compare(a, b); 
      if (comp != 0) { 
       return comp; 
      } 
      if (subclass.isInstance(a) && subclass.isInstance(b)) { 
       return keyExtractor.apply(subclass.cast(a)) 
        .compareTo(keyExtractor.apply(subclass.cast(b))); 
      } 
      return 0; 
     }; 
    } 
} 

अधिक: टिप्पणी का जवाब करने के लिए: नहीं, मैं जरूरी नहीं लगता है कि इस दृष्टिकोण अधिक पठनीय या पोषणीय है। असल में, मेरा मानना ​​है कि पूरा डिज़ाइन अनजान है, क्योंकि कक्षा को जोड़ना बहुत आसान है जो कुल ऑर्डरिंग के गुणों का उल्लंघन करने की तुलना करेगा; मैं अलग-अलग वर्गों की वस्तुओं पर काम करने के आदेश को कैसे स्पष्ट करना चाहता हूं, इसकी स्पष्ट परिभाषा के साथ एक अलग डिज़ाइन की तलाश में हूं। तुलना को संभालने का "सही" तरीका शायद उस अलग डिजाइन पर निर्भर करेगा।

इसी तरह की समस्याओं के लिए, मैं एक compareTo दृष्टिकोण के साथ छड़ी सकता है, जब तक कि मैं किसी अन्य कारण से एक Comparator वापस जाने के लिए एक वर्ग की जरूरत है (जैसे कई orderings Organism रों के लिए परिभाषित कर रहे हैं)। हालांकि, मैं डुप्लिकेशंस को खत्म करने के तरीकों की तलाश कर सकता हूं, यदि प्रत्येक compareTo एक ही संरचना के साथ if कथन है, या ऐसा कुछ है।

+2

क्या आपको लगता है कि मूल कोड में उपclass में 'exampleof' अभिव्यक्ति होने से पहले इस दृष्टिकोण को बनाए रखना और/या बेहतर पठनीय करना आसान होगा? – Balder

+0

@balder मेरा संपादन देखें – ajb

+0

@ajb इस उत्तर के लिए धन्यवाद। मैं डिजाइन के साथ समस्या पर आपसे असहमत नहीं हूं - मुझे यह तथ्य पसंद नहीं है कि यह जटिलता पर सहयोग करने वाले कार्यान्वयन के माध्यम से ही काम करता है। हालांकि मुझे यह देखने में दिलचस्पी होगी कि इसे कैसे प्राप्त किया जाए: अपने इंटरफ़ेस के कार्यान्वयन को अपने स्वयं के ऑर्डरिंग तंत्र को परिभाषित करने के लिए कैसे करें। मुझे यकीन नहीं है कि मैंने किसी भी मानक कोड में एक अच्छा उदाहरण देखा है जिसमें बहुत सारी अनावश्यक जटिलता नहीं है। – sprinter

0

आप की तरह कुछ कर सकते हैं:

return Comparator 
     .comparingInt(Organism::getComplexity) 
     .thenComparing(o-> o instanceof Bacteria ? 
      ((Bacteria) o).getShape() : Bacteria.Shape.ROD); 

तो अगर यह एक जीवाणु है, तो यह आकृतियाँ तुलना, अन्यथा यह एक ही प्रकार जो हमेशा बराबर होते हैं की एक निरंतर तुलना करती है। यदि आप तुलना में उसी प्रकार का उपयोग नहीं करते हैं तो यह संकलित नहीं होगा।

यह एक सामान्य इंटरफ़ेस नहीं है लेकिन शायद यह उन अन्य लोगों की सहायता करेगा जो सीमित संख्या में उप-वर्गों की संपत्तियों की तुलना करने की कोशिश कर रहे हैं।

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