2013-08-09 9 views
8

Mam kod, który pobiera dwuczęściowy wykres jako dane wejściowe i zwraca mapę z kluczem "1" z wartością, która jest listą "węzłów w zestawie1" i kluczem "2", którego wartość jest listą "węzłów w zestawie2" . Teraz mapa jest zmienna. Teoretycznie powinienem użyć kopii obronnej do zwrócenia mapy. Ale w tym przypadku jest to naprawdę wymagane? Wygląda na przesadę.Czy kopie obronne należy ZAWSZE robić?

ex:

class BiPartite { 

    Graph graph; 
    Map bipartite 

    Bipartite(graph) { 
     this.graph = graph; 
    } 

    void calcBipartite() { 
    // calculate map 
    } 

    Map getMap() { 
    // should i make defensive copy ? Appears overkill. 
    } 
} 
+0

Jeśli zwracana wartość jest pochodną, ​​która jest obliczana w locie, nie ma potrzeby wykonywania kopii obronnych. Czy obliczasz wartość zwracaną getMap za każdym razem, gdy wywoływana jest metoda? – HariKrishnan

+4

Należy pamiętać, że osoba dzwoniąca ma już zewnętrzny dostęp do wewnętrznych wartości tego obiektu, ponieważ nie kopiuje się 'wykresu ', zakładając, że" Wykres "jest zmienny. – jpmc26

Odpowiedz

6

To zależy :)

  • można udokumentować swoją klasę odpowiednio, określając, że wrócił Mapa jest zmienny bezpośredni widok na zmienny stan dwuczęściowego obiektu. Nie polecałbym tego jednak.
  • Można zawinąć wewnętrzną mapę za pomocą Collections.unmodifiableMap(map) w dokumencie getMap()i, która odzwierciedla zmienny stan obiektu BiPartite. To może być prawidłowe podejście, o ile obiekt BiPartite nie ma być bezpieczny dla wątków. Jeśli klient chce zachować zwróconą mapę jako stabilną migawkę, może ją skopiować sam. Jeśli nie jest to potrzebne, może skorzystać z operacji szybkiego owijania.
  • Zawsze można zwrócić pełną kopię. Byłoby to najbardziej sensowne, jeśli rzeczywiście utworzysz obiekt bezpieczny dla wątków BiPartite. W takim przypadku będziesz musiał również zsynchronizować wszystkie operacje na wewnętrznej mapie (łącznie z operacją kopiowania mapy!).

Zasadniczo sprowadza się do: Należy zastanowić się, w jaki sposób wykorzystać klasę BiPartite i jej metody, wybrać odpowiednią implementację i wyraźnie udokumentować zarówno zachowanie klasy, jak i jej uzasadnienie.

1

Tak należy, Bo w przeciwnym razie klient może zmienić pole prywatny swojej klasie dzięki czemu klasa zachowywać niewłaściwie.

1

To zależy od konwencji twojego kodu. Postępuję zgodnie z konwencją kopiowania wszystkiego, co chcesz zachować. tj. jest to odpowiedzialność dzwoniącego.

Jest to bardziej wydajne, ale nie jest solidne, jeśli nie wiesz, że rozmówca będzie postępować zgodnie z tą konwencją.

5

Tak, powinieneś zwrócić kopię obronną. Jeśli martwisz się o wykorzystanie zasobów, można powrócić do mapy, która jest niezmienne widok prywatnej mapie:

return Collections.unmodifiableMap(bipartite); 
+0

Tak, właśnie o to mi chodziło. – Joni

+0

Należy zauważyć, że 'Collections.unmodifiableMap()' to * nie * kopia - tylko widok z wyłączonymi wszystkimi operacjami zapisu. Po przeczytaniu (oryginalnej) odpowiedzi łatwo jest pomylić te dwa. – creinig

+1

Moim zdaniem niezmienny widok jest lepszym wyborem niż kopia. Pozostawia to względy wydajnościowe w rękach osoby dzwoniącej; mogą zdecydować, czy muszą wydać i poświęcić czas na tworzenie kopii. Jeśli nie, to w zasadzie mają tanią kopię. – jpmc26

2

słowo „zawsze” jest rzadko kiedy wyjaśniając właściwe wzorce i dobre praktyki programistyczne. Wszystko zależy od kontekstu.

W Twojej przypadku metoda i sama klasa są "pakietami prywatnymi", więc klienci (użytkownicy twojego kodu) nie będą mogli z niego korzystać bezpośrednio. Jeśli wiesz, że nigdy nie przechowujesz ani nie zwracasz tej mapy poza granice tego pakietu, to całkiem bezpiecznie jest powiedzieć, że nie musisz tworzyć kopii obronnej.

0

Kopie defensywne to coś złego, ponieważ większość frameworków java, z którymi się spotkałem, oczekuje, że osoba pobierająca zawsze zwróci tę samą wartość i zrobi to szybko.

Jeśli chcesz, abyś został uratowany od klientów, którzy utracili kod, powinieneś ujawnić tylko metodę calcBipartite() i pozwolić jej zwrócić nowo obliczoną mapę. Klient, który używa tej metody, musi zdecydować, w jaki sposób jest używany obiekt utworzony i ile razy wywoływana jest funkcja calcBartart().

Jeśli jesteś jedynym klientem kodu, nie powinieneś kopiować ani owijać.

Powiązane problemy