3.10 Diseño de programas OO

Anuncio
3.10 Diseño de
programas OO
Patrones de diseño
Patrones de diseño
l
l
l
Factory
l
l
l
Son formas convenientes de reutilizar código
orientado a objetos entre proyectos y
programadores
Promueven que los objetos se ocupen solo de “sus
propios asuntos”.
Un patrón aborda un problema de diseño recurrente
que aparece en situaciones especificas y que
represente una solución a este.
1º Ejemplo de Factory (1/4)
Una “fábrica” es un patrón que devuelve una
instancia de una clase entre un conjunto de
posibilidades dependiendo de la información
proveída.
Generalmente devuelve una clase abstracta
o una interfaz.
El programador no sabe que instancia
específica esta usando.
l
l
Clase para separar un nombre en dos partes.
Clase base con dos hijas.
abstract class Namer{
protected String first;
protected String last;
public String getFirst() {
return first;
}
public String getLast() {
return last;
}
}
1º Ejemplo de Factory (2/4)
class FirstFirst extends Namer{
class LastFirst extends Namer{
public FirstFirst(String s) {
public LastFirst(String s) {
int i = s.lastIndexOf(" " );
int i = s.indexOf("," );
i f (i > 0 ) {
i f (i > 0 ) {
first=s.substring(0, i).trim();
last=s.substring(0,i).trim();
last=s.substring(i + 1).trim();
first=s.substring(i+1).trim();
} else {
public class NameFactory {
public Namer getNamer(String entry) {
int i = entry.indexOf( ",");
if (i > 0)
} else {
first = " ";
last = s;
last = s;
first = " ";
}
return new LastFirst(entry);
else
return new FirstFirst(entry);
}
}
}
1º Ejemplo de Factory (3/4)
}
}
}
}
1
1º Ejemplo de Factory (4/4)
2º Ejemplo de Factory (1/4)
public static void main(String[] args) {
l
NameFactory factory = new NameFactory();
l
Namer namer ;
Fabrica de objetos para realizar loggin
Utilización de configuraciones por defecto
interface Logger{
namer = factory.getNamer("Perez, Juanito") ;
public void doLog(String message, int level);
System.out.println( "First: " + namer.getFirst());
}
System.out.println( "Last: " + namer.getLast());
abstract class AsbtractLogger implements Logger{
private int minLevel;
namer = factory.getNamer("Maria Espinoza") ;
protected AsbtractLogger( int level){
minLevel=level;
System.out.println( "First: " + namer.getFirst());
}
System.out.println( "Last: " + namer.getLast());
public void doLog(String message, int level){
}
if(level>=minLevel)
First: Juanito
doLog(message);
Last: Perez
}
First: Maria
abstract protected void doLog(String message);
}
Last: Espinoza
2º Ejemplo de Factory (3/4)
2º Ejemplo de Factory (2/4)
public class LoggerFactory {
private int defaultLevel=0;
private String defaultDestiny;
class NetLogger extends AsbtractLogger{
public void setDefaultLevel(int l){defaultLevel=l;}
public NetLogger(URL destiny, int minLevel){
public void setDefaultDestiny(String str) {defaultDestiny = str;}
super (minLevel);
public Logger createLogger(){return createLogger(defaultDestiny);}
public Logger createLogger(String destiny){
}
try{
protected void doLog(String message) {
URL url = new URL(destiny);
System.out.println("[NetLogging]" +message);
return new NetLogger(url, defaultLevel);
}
}catch(MalformedURLException mue){}
}
try{
class FileLogger extends AsbtractLogger{
File file = new File(destiny);
if(file.exists())
public FileLogger(File destiny, int minLevel){
return new FileLogger(file,defaultLevel);
super (minLevel);
else
}
throw new FileNotFoundException();
protected void doLog(String message) {
}catch(FileNotFoundException fnfe){}
System.out.println("[FileLogging]"+message);
return null;
}
}
}
}
2º Ejemplo de Factory (3/4)
Singleton
public static void main(String[] args) {
l
LoggerFactory factory = new LoggerFactory();
factory.setDefaultLevel(2);
[NetLogging]test2
factory.setDefaultDestiny("http://log.inf.utfsm.cl") ;
[NetLogging]test3
Logger logger1= factory.createLogger();
[NetLogging]test4
[FileLogging]test2
logger1.doLog("test1" , 1 ) ;
[FileLogging]test3
logger1.doLog("test2" , 2 ) ;
logger1.doLog("test3" , 3 ) ;
[FileLogging]test4
l
Un “singleton” es un objeto que requiere
tener una sola instancia creada de manera
simultanea.
Útil para mejorar rendimiento y asegurar
recursos no compartidos.
logger1.doLog("test4" , 4 ) ;
Logger logger2 = factory.createLogger("test.log" );
logger2.doLog("test1" , 1 ) ;
logger2.doLog("test2" , 2 ) ;
logger2.doLog("test3" , 3 ) ;
logger2.doLog("test4" , 4 ) ;
}
2
1º Ejemplo de Singleton (1/3)
1º Ejemplo de Singleton (2/3)
public class PrintSpooler {
Spooler de impresión.
Solo se permite un numero máximo de
instancias.
l
l
private static i n t instances=0;
private static i n t maxInstances=2;
private PrintSpooler(){}
public static PrintSpooler newSpooler(){
if(instances>=maxInstances)
return null;
else{
instances++;
return n e w PrintSpooler();
}
}
public void finalize(){
instances --;
}
}
1º Ejemplo de Singleton (3/3)
public static void main(String[] args) {
PrintSpooler ps1,ps2, ps3;
2º Ejemplo de Singleton (1/3)
l
l
ps1 = PrintSpooler.newSpooler();
if(ps1!=null) System.out.println( "First spooler created" );
l
Conexión a la base de datos
Una sola instancia
Se puede mezclar con una fabrica
else System.out.println("First spooler not created!" );
ps2 = PrintSpooler.newSpooler();
if(ps2!=null) System.out.println( "Second spooler created");
else System.out.println("Second spooler not created" );
ps3 = PrintSpooler.newSpooler();
if(ps3!=null) System.out.println( "Third spooler created" );
else System.out.println("Third spooler not created") ;
}
2º Ejemplo de Singleton (2/3)
2º Ejemplo de Singleton (3/3)
public class DBConnection {
private static DBConnection instance=null;
private static String defaultSetup;
public static void main(String[] args) {
DBConnection dbc1, dbc2;
private String setup;
DBConnection.setParameters("jdbc:oracle:thin:bd.inf.utfsm.cl/db1");
private DBConnection(String s){setup=s;}
dbc1 = DBConnection.getConnection();
public static void setParameters(String str){defaultSetup=str;};
dbc2 = DBConnection.getConnection();
public static DBConnection getConnection(){
if(instance== null )
if(dbc1==dbc2)
instance = n e w DBConnection(defaultSetup);
System.out.println("Only one connection" );
return instance;
else
}
System.out.println("More than one connection");
public void finalize(){
instance= null ;
}
}
}
3
Patrones de diseño
empresariales
l
l
l
Principalmente para aplicaciones
distribuidas.
Incluyen conceptos de J2EE.
Mantienen complejidad baja y alta
mantenibilidad en sistemas web integrados
con un back-end.
View Helper
l
Motivación
l
l
l
l
Los cambios en las capas de presentación son usuales.
Son difíciles de desarrollar y mantener cuando la lógica de
acceso a datos del negocio y la lógica de formatos de
presentación están mezclados.
Se requiere una separación clara de las tareas
Solución
l
Una vista (View) contiene el código de formato,
delegando las responsabilidades de procesamiento a
una clase que la asiste (Helper).
View Helper
View Helper
Session Facade
Session Facade
l
l
Motivación
l La lógica y los datos del negocio quedan expuestos a los clientes a través
de componente empresariales.
l Esto implica que la capa cliente queda expuesta a la complejidad de las
interfaces de los servicios distribuidos
l Alto acoplamiento, provocando dependencias entre las capas del cliente y
de la lógica.
l Se generan muchas invocaciones de métodos entre el cliente y el servidor,
generando problemas de rendimiento en la red.
l No existe una estrategia uniforme de acceso desde los clientes h acia los
servicios, permitiendo un mal uso de las interfaces de los componentes.
Solución
l Utilizar un componente en el servidor como una fachada que
encapsula la complejidad de las interacciones entre los componentes
empresariales y el cliente, entregándole a este ultimo una estra tegia de
acceso uniforme de menor granularidad.
4
Session Facade
Data Access Object
Motivación
l Las aplicaciones requieren de datos persistentes
l Además pueden requerir acceder a información que reside en
distintos sistemas.
l Los componentes requieren un acceso transparente al lugar de
almacenamiento persistente o a la implementación específica de
la fuente de datos.
Solución
l Utilizar un objeto de acceso a datos (Data Access Object,
DAO) para abstraer y encapsular el acceso a la fuente de
datos. El DAO administra la conexión con la fuente de datos
para recuperar y almacenar los datos.
l
l
Data Access
Object
Data Access Object
Ejemplo completo
l
DAO para recuperar productos e usuarios
l
l
l
l
l
l
DAO para usuarios
XML
Base de datos
Web service
Componentes del negocio para listar y
vender productos
Fachada para encapsular funcionalidad
Cliente que accede a los servicios
public class User {
private int rut;
private String nombre;
public User(String n){setNombre(n);}
public int getPK(){ return rut; }
public void setNombre(String n){nombre=n; }
}
5
DAO para usuarios
DAO para usuarios
class UserDAO {
public static void main(String args []){
private User user ;
public UserDAO(User u){user = u;}
User u = new User("111111");
public boolean load() throws SQLException{
UserDAO dao = new UserDAO(u);
int rut = this.user.getPK ();
try{
user.setNombre("pedrito") ;
dao.load ();
return false;
}
u.setNombre(" Juanito");
public boolean store() throws SQLException{
dao.store();
int rut = this.user.getPK ();
}catch(SQLException sqle ){}
return false;
}
}
public static Collection getUsers (){
return null;
}
}
DAO para productos
DAO para productos
class ProductXMLDAO extends ProductDAO{
public Product[] getProducts( ) {return null; }
public Product[] getFilteredProducts(String string) {return null ;}
public class Product {
public i n t getStock(Product p ) {return 0;}
private String code;
public void decrementStock(Product p ) {}
public String getCode(){
}
return code;
class ProductDBDAO extends ProductDAO{
}
public Product[] getProducts( ) {return null; }
public Product[] getFilteredProducts(String string) {return null ;}
}
public i n t getStock(Product p ) {return 0;}
public void decrementStock(Product p ) {}
abstract class ProductDAO{
public abstract Product[] getProducts ();
}
public abstract Product[] getFilteredProducts(String str);
class ProductWSDAO extends ProductDAO{
public Product[] getProducts( ) {return null; }
public abstract int getStock(Product p);
public Product[] getFilteredProducts(String string) {return null ;}
public abstract void decrementStock(Product p);
public i n t getStock(Product p ) {return 0;}
}
public void decrementStock(Product p ) {}
}
DAO para productos
Componentes del negocio
Factory
class ProductDAOFactory{
l
private static String source= "jdbc:postgresql:localhost:5432/myDb";
private static ProductDAO instance=null;
public static ProductDAO createProductDAO(){
Singleton
if(instance!= null ) return instance;
if(source.equals( "source.xml" ))
l
Un componente para agrupar tareas de
recuperación de información.
Un componente para agrupar tareas de
modificación de información.
instance = n e w ProductXMLDAO();
else if(source.equals ("jdbc:postgresql:localhost :5432/myDb") )
instance = n e w ProductDBDAO( ) ;
else if(source.equals ("http: / /localhost:8081/ws" ))
instance = n e w ProductWSDAO( ) ;
return instance;
}
}
6
class ProductRetriever{
ProductDAO pDao = null;
Componentes del negocio
public ProductRetriever( ) {
Componentes del negocio
pDao = ProductDAOFactory.createProductDAO();
}
public Product getProduct(String code){
Product[] arr= pDao.getFilteredProducts( "code="+code );
class ProductManager{
if(arr.length >0) return arr[0];
ProductDAO pDao = null;
else
public ProductManager(){
throw new IllegalArgumentException
pDao = ProductDAOFactory.createProductDAO ();
("The product code doesn't exist! ");
}
}
public Collection getProducts (){
public boolean dispatchProduct(Product p, User u){
Product[] arr= pDao.getProducts( ) ;
if(pDao.getStock(p)>0)
...
pDao.decrementStock(p);
}
public Collection getUserProducts(User u){
...
Product[] arr = pDao.getFilteredProducts ("buyer= "+u.getPK());
}
...
}
}
}
Fachada de listado y venta:
Fachada de listado y venta
Listado
public class ProductFacade {
private ProductRetriever retriever=new ProductRetriever();
public ProductBean listProducts(){
private ProductManager manager = new ProductManager();
ProductBean bean = new ProductBean ();
private User loggedUser;
bean.setProducts(retriever.getProducts());
public ProductBean listProducts(){
bean.setUserProducts(retriever.getUserProducts(loggedUser ));
...
}
return bean;
}
public boolean sellProduct(String pCode, int quantity ){
...
}
public static class ProductBean{
...
}
}
Fachada de listado y venta:
Fachada de listado y venta:
Venta
Objeto de transferencia
public static class ProductBean{
private Collection products;
private Collection userProducts;
public boolean sellProduct(String pCode, int quantity ){
public Collection getProducts () {
Product p;
return products;
try{
}
p=retriever.getProduct(pCode);
public Collection getUserProducts () {
}catch (IllegalArgumentException iae){
return userProducts;
return false;
}
public void setProducts(Collection collection) {
}
products = collection ;
manager.dispatchProduct(p, loggedUser );
}
return true;
public void setUserProducts(Collection collection) {
}
userProducts = collection ;
}
}
7
Cliente
Cliente
public class Client {
View
ClientView view;
class ClientHelper{
public void showProducts(){
private ProductFacade facade = new ProductFacade();
view.showProducts();
public Collection getProducts(){
}
Helper
}
Collection c = new Vector();
ProductBean bean = facade.listProducts();
class ClientView{
c.addAll(bean.getUserProducts());
private ClientHelper helper = new ClientHelper( ) ;
c.addAll(bean.getProducts());
public void showProducts(){
return c ;
Iterator it = helper.getProducts().iterator();
while (it.hasNext())
System.out.println(it.next());
}
}
}
}
Conclusiones
l
l
l
Clara separación de tareas.
Posibilidad de distribuir objetos.
Definición de paquetes
l
l
l
Las únicas clases publicas son “User”, “Product” y
“ProductFacade”.
El cliente se define en un paquete distinto.
El cliente solo puede acceder a la fachada.
Resumen
l
l
l
l
l
Factory
Singleton
View Helper
Session Facade
Data Access Object
8
Descargar