1
Reutilización del Software
Programación genérica
2
Índice
1.-) Introducción2.-) Contenedores (JGL containers)3.-) Algoritmos (JGL algorithms)4.-) Objetos función (JGL function objects)5.-) Iteradores (JGL iterators)6.-) Ejercicios con JGL
3
Genericidad
Lista
Pila
Cola
Queremos implementar los métodos:sort()greatest()printAll()
4
Genericidad
Lista Pila Cola
sort()greatest()printAll()
sort()greatest()printAll()
sort()greatest()printAll()
Inconvenientes:El código el similar en todos las estructuras (replicación)Qué sucede si añadimos una nueva colección?
(Set, Hash, Vector)
5
Genericidad
Lista Pila Cola
sort(Colección c)greatest(Colección c)printAll(Colección c)
Colección (Interfaz)
hasMoreElements()nextElement()
Algoritmos
implementaimplementaimplementa
usa
Y mas cosas……
6
Genericidad
class Algoritmos {public void printAll (Colección c) {Object o;while (c.hasMoreElements()) {o=c.nextElement();System.out.println(o);}
}}
main() {Pila p=new Pila();Algortimos.printAll(p);}
main() {Colección c=new Cola();Algortimos.printAll(c);}
7
Genericidad
La programación genérica es una técnica que define algoritmos:1. reusables2. implementadados como entidades de primer nivel(clases)3. independientes de los datos sobre los que opera
Normalmente los algoritmos genéricos son utilizados sobre agregados de elementos (pilas, colas, listas, conjuntos. …)
8
JGL- Una librería genérica en Java
http://www.recursionsw.com/
9
¿Qué es JGL?
• La Generic Collection Library for Java™(JGL) es un conjunto de ESTRUCTURAS DE DATOS Y ALGORITMOS REUSABLES.
• JGL complementa a la librería que viene con el JDK (Java Development Kit), la cual contiene un soporte limitado para estructuras de datos y algoritmos.– En JDK existen Vector, Enumeration, Dictionary, ...
10
Componentes principales de la librería JGL
• Containers• Adapters• Algorithms• Function Objects• Iterators
11
Paquetes de la librería JGL
• package com.objectspace.jgl– contiene interfaces, clases e iteradores
• package com.objectspace.jgl.adapters– contiene los adaptadores a arrays nativos de
Java• package com.objectspace.jgl.algorithms
– contiene todos los algoritmos JGL• package com.objectspace.jgl.functions
– contiene las funciones que pueden usarse para modificar algoritmos
12
• package com.objectspace.jgl.predicates– contiene las clases con los predicados
utilizados para especificar orden de elementos dentro de contenedores
• package com.objectspace.jgl.util– contiene algunas clases con utilidades
Paquetes de la librería JGL(II)
13
JGL ContainersLa jerarquia
-------------------------------------------------
Interfaces JDK
14
• La versión JDK 1.5 y por lo tanto la JGL 5.0 permite definir clases e interfaces genéricas (generics)
JGL ContainersCaracterísticas
interface Stack<T>
public interface Stack<T> extends Container<T>
15
• Las clases al igual que las interfaces se definen de manera genérica
JGL ContainersCaracterísticas
public class ListStack<T> implements Stack<T>
16
• Al crear una instancia se especifica la CLASE de elemento que contiene
JGL ContainersCaracterísticas
ListStack<String> pilaStrings=new ListStack<String>o
Stack<String> pilaStrings=new ListStack<String>
• Ahora únicamente se pueden introducir elementos de tipo String, en caso contrario, el compilador detectará un error de tipos
pilaStrings.add(“Esta inserción es correcta”); //OK
pilaStrings.add(new Integer(4)); //Error de compilación
17
• No se pueden almacenar tipos primitivos (char, int,…)– Para ello usar las clases Boolean, Character, Byte, Short,
Integer, Long, Float y Double de java.lang
JGL ContainersCaracterísticas
pilaEnteros.add(new Integer(4));
• Cuando se extrae un elementos de la estructura NO hay que hacer el Casting
Integer numero=pilaEnteros.pop();
18
public class Container1{public static void main(String[] args){Array<String> array = new Array<String>();array.add( "triangle" );array.add( "square" );array.add( "pentagon" );array.add( "hexagon" );System.out.println( "array = " + array );System.out.println( "array.size() = " + array.size() );System.out.println( "array.empty() = " + array.isEmpty() );array.clear();System.out.println( "after array is cleared..." );System.out.println( "array.size() = " + array.size() );System.out.println( "array.empty() = " + array.isEmpty() );}
}
Outputarray = Array(triangle, square, pentagon, hexagon)array.size() = 4array.empty() = falseafter array is cleared...array.size() = 0array.empty() = true
JGL ContainersEjemplo
19
public class Container2 {public static void main( String[] args ) {Array<Integer> array = new Array<Integer>();array.add( new Integer(1) );array.add( new Integer(2));array.add( new Integer(3));Integer i;Enumeration<Integer> iterator = array.elements();while ( iterator.hasMoreElements() ) {
i= iterator.nextElement() System.out.println( i.toString() );
} }
Output123
JGL ContainersEjemplo: Recorrido
20
JGL ContainersLa interfaz Container<T>
interface Container<T>
public interface Container<T>extends java.lang.Cloneable, java.io.Serializable, java.util.Collection<T>
21
JGL Containers
22
JGL SequencesLa interfaz Sequence<T>
at/putfront/backpopFront/popBackpushFront/pushBackMétodos
indexOf
count
replaceremove
devuelve/reemplaza el elemento en la posición especificadadevuelve el primer/último elementoelimina y devuelve el elemento al principio/finalinserta un elemento al principio/final
devuelve la posición de un elemento concreto
cuenta el número de elementos coincidentes con uno
reemplaza un valor por otroborra un valor concreto
Significado
public interface Sequence<T>extends Container<T>, java.util.List<T>
23
public class Sequences2 {public static void main( String[] args ) {Deque<String> deque =new Deque<String>();deque.pushBack( "APE" );deque.pushBack( "BAT" );deque.pushFront(”BAT");deque.add( "cat" ); deque.add( "bat" ); deque.add( "bat" );deque.add( "cat" ); // add ES SINONIMO DE pushBackSystem.out.println( "deque = " + deque );System.out.println( "deque.count( bat ) = " + deque.count( "bat" ) );int index = deque.indexOf( "bat" );System.out.println( "deque.indexOf( bat ) = " + index );deque.remove( index );System.out.println( "After deque.remove( " + index + " ) = " + deque );deque.replace( 0, 1, "BAT", "bat" );System.out.println( "After deque.replace( 0, 1, BAT, bat ) = " + deque );System.out.println( "deque.remove( cat ) = " + deque.remove( "cat" ) );System.out.println( "After deque.remove( cat ) = " + deque ); } }
deque = Deque( BAT, APE, BAT, cat, bat, bat, cat )deque.count( bat ) = 2deque.indexOf( bat ) = 4After deque.remove( 4 ) = Deque( BAT, APE, BAT, cat, bat, cat )After deque.replace( 0, 1, BAT, bat ) = Deque( bat, APE, BAT, cat, bat, cat )deque.remove( cat ) = 2After deque.remove( cat ) = Deque( bat, APE, BAT, bat )
JGL Containers => SequencesEjemplo
24
• Stack es una estructura de pila (LIFO). Por defecto, para su almacenamiento interno utiliza un Array, pero puede cambiarse.
• Queue es una estructura de cola (FIFO). Por defecto, para su almacenamiento interno utiliza una Slist, pero puede cambiarse.
• PriorityQueue es una estructura de cola con los elementos ordenados y que devuelve los elementos según dicho orden. Por defecto, para su almacenamiento interno utiliza un Array, pero puede cambiarse
CONTAINERS QUEUES & STACKSJGL Queues y Stacks
<<interface>>Queue
<<interface>>PriorityQueue
<<interface>>Stack
ListQueue ListPriorityQueue ListStack
<<interface>>Container
25
Aparte de los métodos de CONTAINER, Stack y Queue tienen los métodos
Los métodos para PriorityQueue son también push y pop.Al crear un nuevo objeto de dicho tipo se le puede dar un predicado por el cual se ordenen los elementos en la cola.
Por ejemplo: GreaterString()
JGL Queues y Stacks
poppush inserta un nuevo elemento en la Pila/Cola
devuelve el último/primer elemento insertado en la Pila/Cola
26
interface Stack<T>
public interface Stack<T> extends Container<T>
27
interface Queue<T>
public interface Queue<T>extends Container<T>
28
interface PriorityQueue<T>
public interface PriorityQueue<T> extends Container<T>
29
public class Stacks1 {public static void main( String[] args ) {Stack<String> stack = new Stack<String>();stack.push( "bat" );stack.push( "cat" );stack.push( "dog" );System.out.println( "stack = " + stack );System.out.println();System.out.println( "Non-destructively enumerate the Stack." );Enumeration<String> e = stack.elements();while ( e.hasMoreElements() )System.out.println( e.nextElement() );
System.out.println();System.out.println( "Pop and print each element." );while ( !stack.isEmpty() )System.out.println( stack.pop() );
}}
Outputstack = Stack( Array( bat, cat, dog ) )
Non-destructively enumerate the Stack.batcatdog
Pop and print each element.dogcatbat
JGL Queues y StacksEjemplo
30
public class Stacks5 {public static void main( String[] args ) {// Utiliza el predicado GreaterString para comparar elementos. PriorityQueue<String> queue = new PriorityQueue<String>(
new GreaterString<String>() );queue.push( "cat" );queue.push( "dog" );queue.push( "ape" );queue.push( "bat" );queue.push( "fox" );queue.push( "emu" );System.out.println( "Pop and print each element." );while ( !queue.isEmpty() )System.out.print( queue.pop() + " ");
} }
Output
Pop and print each element.ape bat cat dog emu fox
JGL Queues y StacksEjemplo
31
JGL Array adapters
• Los algoritmos genéricos de JGL se pueden aplicar a contenedores JGL, arrays nativos de Java y a estructuras de datos JDK.
• Para ello existen unas clases adaptadores que hacen que los arrays nativos actúen como contenedores JGL (JGL Container)
32
JGL Array adapters
add()clear()clone()
Container
IntArray
implementa
int[]usa
class IntArray<T> implements Container<T> {int[] myArray;IntArray(int[] pArray){ myArray=pArray;}public void add(Object o)public void clear()……..
}
33
OutputPrinting with JGL adapter: (0, 3, 6, 0, 2, 3, 0, 7)Iterate fordwards :(03602307)And iterate backwards = 70320630)
JGL Array adaptersEjemplo: Recorrido arrays nativos
public class Adapters1 { public static void main(String[] args) {int[] nativeArray = new int[]{ 0, 3, 6, 0, 2, 3, 0, 7 }; List<Integer> intArray = new IntArray<Integer>(nativeArray);System.out.println( "Printing with JGL adapter: " + intArray ); // Now, treat the array like a list. ListIterator<Integer> iter = intArray.listIterator(); System.out.print( "Iterate forwards: " ); while ( iter.hasNext() )
System.out.print( iter.next() ); System.out.print( "\nAnd iterate backwards: " ); while ( iter.hasPrevious() ) System.out.print( iter.previous() );
}
34
Outputint[]( 5, -1, 3, 6, 2, 3, 1, 7, -2 )Values greater than 2: 5Replace negative values with 0: int[]( 5, 0, 3, 6, 2, 3, 1, 7, 0 )
Counting.countIf yReplacing.replaceIf
SON JGL ALGORITHMS(se trata más adelante)
JGL Array adaptersEjemplo: Utilizando algoritmos
public class Adapters2 { public static void main(String[] args) { int[] nativeArray = new int[]{ 5, -1, 3, 6, 2, 3, 1, 7, -2 }; // Wrap the native array List<Integer> intArray = new IntArray<Integer>(nativeArray );System.out.println( intArray ); // Count the values greater than 3 UnaryPredicate<Integer> greaterThan2 = new BindSecondPredicate<Integer>(
new GreaterNumber<Integer>(), new Integer(2)); int count = Counting.countIf(intArray, greaterThan2); System.out.println( "Values greater than 2: " + count ); // Replace negative values with 0 Replacing.replaceIf(intArray, new NegativeNumber(), new Integer(0)); System.out.println( "Replace negative values with 0: " + intArray );
}
35
Ejercicio
• ¿Cómo definirías una Pila de enteros, utilizando como estructura interna de almacenamiento un array nativo de enteros ?– Modela el diagrama de clases– Crea una instancia Pila y añade un
elemento
36
• JGL proporciona más de 50 algoritmos reusables (desde un filtrado a un quicksort) que pueden ser aplicados a contenedores JGL, JDK y arraysnativos de Java (a través de adapters).
• Cada algoritmo se implementa como un método estático y público de una clase.– Las clases son: Applying, Comparing, Copying,
Counting, Filling, Filtering, Finding, Heap, MinMax, Permuting, Printing, Removing, Replacing, Reversing, Rotating, SetOperations, Shuffling, Sorting, Swapping, Transforming
– No pueden crearse instancias de estas clases– Se encuentran en com.objectspace.jgl.algorithms
JGL algorithms
37
public class Algorithms3 {public static void main( String[] args ) {
Slist<Integer> list = new SList<Integer>();list.add( new Integer( -1 ) );list.add( new Integer( 1 ) );list.add( new Integer( -2 ) );list.add( new Integer( 1 ) );list.add( new Integer( -3 ) );System.out.println( "list = " + list );
Object value = new Integer( 1 );int n1 = Counting.count( list, value );System.out.println( "Occurences of " + value + " = " + n1 );
int n2 = Counting.countIf( list, new NegativeNumber<Integer>() );System.out.println( "Occurences of a negative = " + n2 );}
}
Output
list = SList( -1, 1, -2, 1, -3 )Occurences of 1 = 2Occurences of a negative = 3
NegativeNumber() ES JGL PREDICATE(se trata más adelante)
JGL algorithmsEjemplo Counting
38
public class Algorithms4{public static void main( String[] args ){int ints[] = { 3, 7, 8, 2, -5, 8, 9, -2 };IntArray array = new IntArray( ints );System.out.println( "array = " + array );
Integer negative = Finding.detect( array, new NegativeNumber<Integer>() );System.out.println( "first negative = " + negative );
boolean some = Finding.some( array, new NegativeNumber<Integer>() );System.out.println( "some items are negative = " + some );}
}
Output
array = int[]( 3, 7, 8, 2, -5, 8, 9, -2 )first negative = -5some items are negative = true
JGL algorithmsEjemplo Finding
39
• Muchos de los algoritmos y de los contenedores JGL requieren que se especifique un objeto función para poder ejecutar sus operaciones
• Hay dos tipos de objetos función:– Predicados, devuelven valores booleanos y se usan
para ordenar elementos o activar ejecuciones de acciones.
• Se encuentran en com.objectspace.jgl.predicates– Funciones generales, ejecutan operaciones y
devuelven objetos• Se encuentran en com.objectspace.jgl.functions
• Se crean instancias de dichas clases de objetos función
JGL Function Objects
40
• Los predicados se utilizan para ejecutar acciones u ordenar elementos. Devuelven siempre un valor booleano.– El algoritmo countIf() permite contar elementos que
cumplen una determinada condición booleana(expresada mediante un predicado unario).
– El algoritmo sort() ordena según un criterio de ordenación (expresado mediante un predicado binario)
• JGL define interfaces para predicados unarios y binarios – La interfaz UnaryPredicate tiene un método llamado execute() que toma un único parámetro un objeto
– La interfaz BinaryPredicate define un método execute() que toma como parámetros dos objetos
JGL Function ObjectsPredicates
41
La interfaz UnaryPredicate
• public interface UnaryPredicate<T>
42
JGL Function ObjectsEjemplo: Unary Predicate. Mayores que 5
public class Functions {public static void main( String[] args ) {
int array[] = { 5, 6, 7, 4, 3 };IntArray ints = new IntArray( array );UnaryPredicate<Integer> predicate = new GreaterThan5<Integer>();int n = Counting.countIf( ints, predicate );System.out.println( “Greater than 5 in " + ints + " = " + n );} }
public final class GreaterThan5<T> implements UnaryPredicate<T> {public boolean execute(T number) {
return ( number.intValue()>5);}
}
43
JGL Function ObjectsEjemplo: Binary Predicate. Sort
public class Functions {public static void main( String[] args ) {
Deque deque=new Deque();//insert data deque.add(“cat”);......BinaryPredicate comparator=new GreaterString<String>();Sorting.sort(deque, comparator);
} }
public class GreaterString<T> implements BinaryPredicate<T,T> {public boolean execute(T first, T second) {
return (first.toString()).compareTo(second.toString() )> 0;}
}
44
• La librería de JGL nos ofrece un conjunto de predicados YA predefinidos
• En la documentación de JGL aparece:– Todos los predicados unarios predefinidos– Todos los predicados binarios predefinidos– Todas los algoritmos JGL que aceptan un predicado
JGL Function ObjectsPredicates
45
• Las funciones generales se utilizan para aplicar operaciones matemáticas a todos los elementos de una colección.– El algoritmo transform() puede ser usado para
obtener una nueva secuencia a partir de otra donde a todos los elementos se les cambia de signo.
• JGL define interfaces para funciones unarias y binarias – La interfaz UnaryFunction tiene un método llamado execute() que toma un objeto como parámetro y devuelve un objeto
– La interfaz BinaryFunction tiene un método execute()que toma como dos objetos como parámetros y devuelve un objeto
JGL Function ObjectsGeneral Functions
46
public class Functions5 {public static void main( String[] args ) {Deque<Integer> deque = new Deque<Integer>();deque.add( new Integer( 4 ) );deque.add( new Integer( -2 ) );deque.add( new Integer( 3 ) );UnaryFunction<Integer,Integer> function =
new NegateNumber<Integer>();System.out.println( "before = " + deque );Transforming.transform( deque, deque.begin(), function );System.out.println( "after = " + deque );}
}
Output
before = Deque( 4, -2, 3 )after = Deque( -4, 2, -3 )
public class NegateNumber<T> implements UnaryFunction<T,T> {public T execute (T number) {
return -1 *number ;}
}
JGL Function ObjectsGeneral Functions
47
import com.objectspace.jgl.*;import com.objectspace.jgl.adapters.*;import com.objectspace.jgl.algorithms.*;import com.objectspace.jgl.functions.*;public class Algorithms9 {
public static void main( String[] args ){ int ints1[] = { 1, 3, 5, 2 };
Array<Integer> array = new Array<Integer>();IntArray<Integer> intArray1 = new IntArray<Integer>( ints1 );UnaryFunction<Integer,Integer> function = new NegateNumber<Integer>();Transforming.transform( intArray1, array, function );System.out.println( "ints1 = " + intArray1 );System.out.println( "array = " + array );System.out.println();int ints2[] = { 2, 4, 2, 3 };int ints3[] = { 3, 6, 2, 1 };SList<Integer> list = new Slist<Integer>();IntArray<Integer> intArray2 = new IntArray<Integer>( ints2 );IntArray<Integer> intArray3 = new IntArray<Integer>( ints3 );BinaryFunction<Integer,Integer> function2 = new TimesNumber<Integer>();Transforming.transform( intArray2, intArray3, list, function2 );System.out.println( "ints2 = " + intArray2 );System.out.println( "ints3 = " + intArray3 );System.out.println( "list = " + list );}}
Output
ints1 = int[]( 1, 3, 5, 2 )array = Array( -1, -3, -5, -2 )
ints2 = int[]( 2, 4, 2, 3 )ints3 = int[]( 3, 6, 2, 1 )list = SList( 6, 24, 4, 3 )
48
public class Algorithms1 {public static void main( String[] args ) {
Array<String> array1 = new Array<String>();array1.add( "cat" );array1.add( "monkey" );array1.add( "goat" );Applying.forEach( array1, new Print<String>() );SList<Integer> list = new SList<Integer>();list.add( new Integer( 3 ) );list.add( new Integer( 7 ) );list.add( new Integer( 4 ) );Integer total = Applying.inject( list, new Integer( 0 ), new PlusNumber<Integer>() );System.out.println( "list = " + list + ", total = " + total ); }}
class Print<T> implements UnaryFunction<T,T> {public T execute( T object ) {
System.out.println(object.toString() );return null; // Not used. }}
Output
catmonkeyPRINT goatlist = SList( 3, 7, 4 ), total = 14
49
JGL Function ObjectsGeneral Functions
• La librería de JGL nos ofrece un conjunto de funciones YA predefinidos
• En la documentación de JGL aparece:– Todas las funciones unarias predefinidas– Todas las funciones binarias predefinidas– Todos los algoritmos JGL que aceptan una función
50
• Los objetos predicado BindFirstPredicate y BindSecondPredicate permiten fijar el primer o segundo argumento de un predicado binario
JGL Function ObjectsBinders
public class Functions5 {public static void main( String[] args ) {DList<String> list = new DList<Integer>();list.add(“rojo”);list.add(“amarillo”);list.add(“verde”);list.add(“azul”);UnaryPredicate<String> predicate=
new BindSecondPredicate(new GreaterString<String>(), “ambar”)int n =Counting.countIf(list,predicate);}
}
51
•Los objetos función UnaryComposePredicate y BinaryComposePredicate permiten aplicar una función secundaria a cada operando antes de aplicar el predicado principal.
•Se pueden crear funciones objeto propias–implementando el interfaz apropiado: UnaryPredicateBinaryPredicate,UnaryFunction,BinaryFunction
–y definiendo el método execute()
JGL Function ObjectsComposers
52
JGL Function ObjectsComposers
Ejemplo: Ordenar un Array de Strings, en base al número de caracteres
public class Functions7 {public static void main( String[] args ) {Array<String> array=new Array<String>();list.add(“rojo”);list.add(“amarillo”);list.add(“verde”);BinaryPredicate<String,String> comparator=
new BinaryComposePredicate(new GreaterNumber<Integer,Integer>(),new LegthString<String, Integer>(),new LegthString<String,Integer>() );
Sorting.sort(array, comparator);}
}