È giusto interrompere la relazione "è una" se voglio solo parte di una funzionalità di classe?

0

Ho fatto una domanda sull'estensione di TreeMaps in TreeMaps "ordina per valore" sul sito "revisione codice" su StackOverflow. Sulla base della risposta, ho riscritto il codice. Mi piace. Ma sembra che io stia usando solo trucchi. O forse questo è un modo legittimo per scrivere software? Qualcuno può dare un'occhiata:

public class ToolBox {
    public interface SortedMapByValue {
        void put(Object key, Integer val);
        Set<Map.Entry<Object, Integer>> entrySet();        
    }

    public static SortedMapByValue getInstanceSortedMapByValue() {
        class MyComp implements Comparator {
            Map<Object, Integer> sharedMap;

            public int compare(Object key1, Object key2) {
                if(key1.equals(key2)) { return 0; }

                Integer val1 = sharedMap.get(key1);
                Integer val2 = sharedMap.get(key2);

                if(val1 > val2) return -1; 
                return 1;
            }     
        }

        class MyMap<K> extends TreeMap<K, Integer> {
            Map<Object, Integer> sharedMap = new HashMap<Object, Integer>();
            MyMap(Comparator comp) {
                super(comp);
            }

            @Override
            public Integer put(K key, Integer val) {
                if(sharedMap.containsKey(key)) {
                    super.remove(key);
                    val += sharedMap.get(key);
                }
                sharedMap.put(key, val);
                super.put(key, val);
                return val;
            }
        }

        class TreeMapByValue implements SortedMapByValue {
            private MyMap<Object> realMap;

            public TreeMapByValue(MyMap myMap) { this.realMap = myMap; }

            public void put(Object key, Integer val) {
                realMap.put(key, val);
            }

            public Set<Map.Entry<Object, Integer>> entrySet() {
                return realMap.entrySet();
            }
        }

        MyComp myComp = new MyComp();
        MyMap<Object> myMap = new MyMap(myComp);
        myComp.sharedMap = myMap.sharedMap;

        SortedMapByValue treeMapByValue = new TreeMapByValue(myMap);
        return treeMapByValue;
    }
} 

La domanda è se sia giusto scrivere classi fragili e che rompono le apis di una classe super, a patto che le sposti in un metodo statico? TreeMapByValue non interrompe la relazione "è una" con TreeMap solo perché lo nascondo. Sembra un trucco, ma forse è un modo standard per programmare? Non lo so.

btw: il titolo si riferisce al mio volere l'algoritmo di ordinamento "rosso-nero" di TreeMap, ma non volevo quello che dice l'API riguardo all'ordinamento. Ho mantenuto l'algoritmo, ma ho rotto l'api. Ma poi mi sono nascosto facendo questo.

Si prega di ignorare la mia completa ignoranza dei farmaci generici. Li studierò abbastanza presto.

    
posta red shoe 18.03.2015 - 23:01
fonte

2 risposte

0

MyMap sovrascrive solo un singolo metodo. L'implementazione dell'interfaccia non fa altro che delegare all'istanza MyMap . Potresti facilmente scrivere questo nell'implementazione dell'interfaccia.

class TreeMapByValue implements SortedMapByValue, Comparator {
    private Map<Object, Integer> sharedMap;
    private TreeMap<Object, Integer> tree;

    public TreeMapByValue() {
        sharedMap = new HashMap<Object, Integer>();
        tree = new TreeMap<Object, Integer>(this);
    }

    public void put(Object key, Integer val) {
        if(sharedMap.containsKey(key)) {
            tree.remove(key);
            val += sharedMap.get(key);
        }
        sharedMap.put(key, val);
        tree.put(key, val);
        return val;
    }

    public Set<Map.Entry<Object, Integer>> entrySet() {
        return realMap.entrySet();
    }


    public int compare(Object key1, Object key2) {
        if(key1.equals(key2)) { return 0; }

        Integer val1 = sharedMap.get(key1);
        Integer val2 = sharedMap.get(key2);

        if(val1 > val2) return -1; 
        return 1;
    }    
}

Ora hai solo una lezione. Non esiste un'istanza condivisa che deve essere esplicitamente assegnata a un'istanza di classe diversa. Non c'è alcuna preoccupazione sul modo in cui la classe base viene sovrascritta. Inoltre, il metodo factory non è più necessario poiché l'inizializzazione non è più passaggi. Se non vuoi esporre compare() , puoi spostarlo in una classe interna privata.

  • sharedMap e tree sono nomi di variabili errate. I nomi dovrebbero fornire una descrizione di ciò che contengono o del motivo per cui vengono utilizzati.

  • Sii coerente con le tue dichiarazioni if. A volte sono allineati con parentesi graffe. A volte sono allineati senza parentesi graffe. La mia preferenza è di non usare mai una riga e usare sempre parentesi graffe.

risposta data 19.03.2015 - 15:29
fonte
2

È un e ha una linea guida ragionevole, molto utile quando stai imparando, ma in pratica non dovresti mai usare l'ereditarietà a meno che non sia così evidente che è necessario che non ci siano domande.

L'ereditariene spesso sembra una soluzione molto più ordinata, ma le persone che lo hanno utilizzato in modo approfondito hanno imparato che a lungo andare porta a un codice di manutenzione difficile.

    
risposta data 19.03.2015 - 00:34
fonte

Leggi altre domande sui tag