Herança vs Composição Herança: class B extends A B is a A Composição: class B { A a;... B uses a A ou B has a A A is a component of B 94 Herança vs Composição Apesar da herança ser uma forma poderosa de conseguir reutilizar código, nem sempre é a forma mais apropriada para o conseguir O uso de herança inapropriadamente conduz a programas frágeis relativamente a mudanças! A herança viola o princípio da encapsulação, o que pode ser perigoso! Ao herdar a implementação de uma classe, a subclasse fica dependente de detalhes de implementação dessa classe para funcionar apropriadamente e portanto sujeita a deixar de funcionar se a super-classe for alterada 95
Herança vs Composição A utilização da herança deve se reduzir essencialmente a! classes na mesma package e portanto sob o controlo dos mesmos programadores! a classes especificamente desenhadas para serem estendidas, nomeadamente com documentação preparada para esse fim, como acontece com as classes abstractas e classes de frameworks OO Não usar herança se as condições seguintes não se aplicarem todas:! A subclasse expressa "is a special kind of" e não "is a role played by a.! Uma instância da subclasse nunca necessita de se tornar um objecto de uma outra classe.! A subclasse apenas estende as responsabilidades das suas superclasses. 96 Herança vs Composição Exemplo Pretende-se uma versão de um HashSet que além de tudo o que tem o HashSet disponibilize um método que informa quantas tentativas de inserção de elementos no conjunto foram realizadas. Qual o mecanismo mais apropriado? 97
Solução com Herança public class InstrumentedHashSet<T> extends HashSet<T> { // The number of attempted element insertions private int addcount = 0; public InstrumentedHashSet() { public InstrumentedHashSet(Collection<T> c) { super(c); public InstrumentedHashSet(int initcap, float loadfactor) { super(initcap, loadfactor); public boolean add(t o) { addcount++; return super.add(o); public boolean addall(collection<? extends T> c) { addcount += c.size(); return super.addall(c); public int getaddcount() { return addcount; 98 Solução com Herança O uso da herança neste caso é inapropriado. O que acontece por exemplo se executarmos InstrumentedHashSet<String> s = new InstrumentedHashSet<String> (); s.addall(arrays.aslist(snap","crackle","pop"); O método addall na classe HashSet invoca add mas a classe HashSet não documenta este detalhe de implementação. Uma opção bastante razoável dado que é uma opção de implementação que pode haver interesse em vir a modificar no futuro O que acontece se eliminássemos a redefinição do addall? O que acontece se numa nova release a classe HashSet suportar a inserção de elementos no conjunto através de novos métodos? 99
Solução com Composição Conhecida como Wrapper Class! public class InstrumentedSet<E> implements Set<E> { private final Set<E> s; private int addcount = 0; public InstrumentedSet(Set<E> s) { this.s = s; public boolean add(e o) { addcount++; return s.add(o); public boolean addall(collection<? extends E> c) { addcount += c.size(); return s.addall(c); public int getaddcount() {return addcount; Solução Correcta: Uso de Composição // Forwarding methods Além public da correcção void clear() que { s.clear(); outras vantagens tem esta solução? public boolean contains(object o) { return s.contains(o); public boolean isempty() { return s.isempty(); public int size() { return s.size(); public Iterator<E> iterator() { return s.iterator(); public boolean remove(object o) { return s.remove(o); public boolean containsall(collection<?> c){ return s.containsall(c); public boolean removeall(collection<?> c){ return s.removeall(c); public boolean retainall(collection<?> c){ return s.retainall(c); public Object[] toarray() { return s.toarray(); public <T> T[] toarray(t[] a) { return s.toarray(a); public boolean equals(object o) { return s.equals(o); public int hashcode() { return s.hashcode(); public String tostring() { return s.tostring(); 100 Desenvolvimento C. Objectos 11/12 Herança vs Composição Em geral deve-se preferir a composição à herança Classes desenhadas para ser estendidas devem ter documentação apropriada, nomeadamente devem documentar de que forma usam os métodos que podem ser redefinidos public boolean remove(object o) Exemplo AbstractCollection Removes a single instance of the specified element from this collection, if it is present (optional operation). ( ) This implementation iterates over the collection looking for the specified element. If it finds the element, it removes the element from the collection using the iterator s remove method. Note that this implementation throws an UnsupportedOperationException if the iterator returned by this collection s iterator method does not implement the remove method. Se classe não foi desenhada e documentada para ser estendida de forma segura, proibir que sejam definidas sub-classes 101
Conhecer e utilizar bibliotecas e frameworks standard Existem muitas vantagens na utilização de bibliotecas e frameworks standard o tirar partido do conhecimento dos peritos que as escreveram e a experiência daqueles que já a usaram exemplo: gerar num aleatório entre 0 e n o não perder tempo na escrita de soluções adhoc só marginalmente relacionadas com a aplicação em desenvolvimento o desempenho do código disponível tipicamente melhora com o tempo, sem esforço da nossa parte No caso do Java, é recomendável o conhecimento do java.util e java.lang Nomeadamente, a framework das Collections é um dos elementos fundamentais na base de conhecimento de qualquer programador 102 Collections Framework É uma arquitectura unificada para representar e manipular colecções As principais vantagens da utilização desta framework são: Reduz esforço de programação fornecendo estruturas de dados e algoritmos que desta forma não necessitam de ser programados. Melhora o desempenho fornecendo implementações eficientes de estruturas de dados e algoritmos úteis. Uma vez que as várias implementações de cada interface podem ser trocadas umas pelas outras, os programas podem facilmente ser ajustados modificando as implementações usadas. Fornece a interoperabilidade entre APIs não relacionados estabelecendo uma linguagem comum para passar e receber colecções. Reduz o esforço requerido para aprender APIs eliminando a necessidade de aprender múltiplas APIs. Promove a reutilização de software fornecendo um interface standard para colecções e algoritmos para manipulá-las. 103
Collections Framework Interfaces - Representa diferentes tipos de colecções tais como conjuntos, listas e maps. Estes interfaces formam a base deste framework. Collection, Set, List, Queue, Deque SortedSet, NavigableSet, BlockingQueue, BlockingDeque Map, SortedMap, NavigableMap, ConcurrentMap, ConcurrentNavigableMap 104 Collections Framework Implementações Genéricas Outras Implementações Set : EnumSet Queue: PriorityQueue Map: EnumMap, WeakHashMap 105
Collections Framework Implementações Abstractas Implementações parciais de interfaces da framework que facilitam o desenvolvimento de implementações específicas. o AbstractCollection a Collection that is neither a Set nor a List. At a minimum, you must provide the iterator and the size methods. o AbstractSet a Set; use is identical to AbstractCollection. o AbstractList a List backed up by a random-access data store, such as an array. At a minimum, you must provide the positional access methods (get,set, remove, and add) and the size method. The abstract class takes care of listiterator (and iterator). o AbstractSequentialList a List backed up by a sequential-access data store, such as a linked list. At a minimum, you must provide the listiterator and size methods. The abstract class takes care of the positional access methods. (This is the opposite of AbstractList.) o AbstractQueue at a minimum, you must provide the offer, peek, poll, and size methods and an iterator supporting remove. o AbstractMap a Map. At a minimum you must provide the entryset view. This is typically implemented with the AbstractSet class. If the Map is modifiable, you must also provide the put method. 106 Collections Framework Porquê programar outras implementações dos interfaces das Collections?! Persistência! Específico da Aplicação: Um Map não modificável contendo valores lidos de sensores, sendo as chaves as localizações (em resposta a um get)! Melhor Desempenho em utilização específica: Uma List contendo muitos elementos repetidos (ocorrem por exemplo no processamento de texto).! Funcionalidade melhorada.! Conveniência: Se são precisas com frequência instâncias de List apenas com Integers consecutivos. 107
Collections Framework Algorithms Métodos de classe que executam funções úteis sobre as colecções. Exemplos: Sorting static T extends Comparable<? super T>> Collections.sort(List<T>) Shuffling static Collections.shuffle(List<?>) Routine Data Manipulation Collections.reverse reverses the order of the elements in a List. Collections.fill overwrites every element in a List with the specified value. Collections.copy takes two arguments, a destination List and a source List, and copies the elements of the source into the destination, overwriting its contents. The destination List must be at least as long as the source. If it is longer, the remaining elements in the destination List are unaffected. Collections.swap swaps the elements at the specified positions in a List. Collections.addAll adds all the specified elements to a Collection. The elements to be added may be specified individually or as an array. 108 Collections Framework Searching <T> int Collections.binarySearch(List<? extends Comparable<? super T>> col, T key) Finding Extreme Values... Collections.min(Collection<? extends T>)...Collections.max(Collection<? extends T>) Composition Collections.frequency (Collection<?>,Object) counts the number of times the specified element occurs in the specified collection Collections.disjoint (Collection<?>,Collection<?>) determines whether two Collections are disjoint; that is, whether they contain no elements in common 109