Posts

Parsear XML con java

De esto se pueden encontrar miles de ejemplos por la red. En mi caso tenía hecho alguno, el problema es que el código era del año 2001. Y sigue funcionando pero tirando de un fichero jar que contiene unas librerías que vete a saber tú. El caso es que he tratado de hacer un ejemplo de esto con material más actualizado tal y como se cuenta en la web oficial de oracle-java (quién lo diría en el 2001). Bueno, al lío:

Este sería el fichero XML:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE PROPERTIES SYSTEM "properties.dtd">
<PROPERTIES>
    <PROPERTY NAME="system_version" >1.0.01    </PROPERTY>
    <PROPERTY NAME="loglevel" >1</PROPERTY>
    <PROPERTY NAME="logfile" >Data/log/output.log</PROPERTY>
    <PROPERTY NAME="multiuser_y_n" >y</PROPERTY>
    <PROPERTY NAME="server_y_n" >y</PROPERTY>
    <PROPERTY NAME="language" >en</PROPERTY>
    <PROPERTY NAME="db_type" >sql</PROPERTY>
    <PROPERTY NAME="jdbc_driver" >sun.jdbc.odbc.JdbcOdbcDriver</PROPERTY>
    <PROPERTY NAME="jdbc_url" >jdbc:odbc:pruebas</PROPERTY>
    <PROPERTY NAME="jdbc_user" ></PROPERTY>
    <PROPERTY NAME="jdbc_password" ></PROPERTY>
    <PROPERTY NAME="init.d" >Data/etc/init.d</PROPERTY>
</PROPERTIES>

Y como se puede ver debe seguir los dictados de un fichero DTD, que en este caso es muy sencillo y es este:

<?xml version="1.0" encoding="UTF-8"?>
<!-- P. Al. -->
<!-- Generic properties file-->
<!ELEMENT PROPERTIES (PROPERTY*)>
<!ELEMENT PROPERTY (#PCDATA)>
<!ATTLIST PROPERTY
    NAME CDATA #REQUIRED
>

Como ya sabrás a estas alturas de siglo existen dos formas básicas de leer un fichero XML desde un programa: una es cargando todo el fichero de golpe.

En este caso he hecho un parser de SAX usando las librerías más simples y menos exóticas posible. Ojo!! para que valida el tema del uso del DTD hay que meter los métodos de error (error, fatalError, warning), porque si no es así no nos empanaremos.


Mock Objects con Mockito

mockito es un framework para trabajar con objetos mock, es decir objetos falsos o simulados. Mockito trata de ser más simple de usar que otras librerías predecesoras como jmock o easymock.

¿Para qué necesitamos objetos simulados? por muchos motivos cuando queremos hacer pruebas unitarias de nuestras clases puede que dependamos de otras clases que tengan alguna pega:

- Son lentas (jdbc, redes, ...)

- No devuelven un resultado concreto

- No se tienen a mano o dependen de algo externo.

- Sencillamente aún no están creadas

En fin, el caso es que puede que haya objetos que necesitemos simularlos a la hora de poder hacer test unitarios de nuestras clases.

Vamos a ver un par de ejemplos en los que se crea una instancia de la clase List falsa y otro ejemplo en el que creamos un BufferedReader de palo.

Mocked List

import static org.mockito.Mockito.*;

import java.util.List;
/**
 * @author Pello Altadill
 * @greetz ñañañaa MOOOOOOOOOCK (vuvuzela)
 */
public class MockList {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // We create a mock list using List interface
        // So, this is a false or mocked list
        List mockedList = mock(List.class);
        
        // We add something to the list
        mockedList.add("Example");
        mockedList.add("Another example");

        // This will return null
        System.out.println("Is anything there?: " + mockedList.get(0));
        
        
        // Now we establish: when we call get(0) on out list we
        // want to return "Pain in the ass"
        // This is Stubbing
        when(mockedList.get(0)).thenReturn("Pain in the ass");
        
        // We verify that we have stubbed this invocation
        // nothing will happen in this case.
        verify(mockedList).add("Example");
        
        // Now, this will return: "Pain in the ass"
        System.out.println("Let's see: " + mockedList.get(0));
        
        // And this one will return  null
        System.out.println("And what about this: " + mockedList.get(1));
        
        // This will throw an Exception because add("Another Exception")
        // invocation is not stubbed
        verify(mockedList).add("Another Example");
        
    }

}
 

Mocked BufferedReader

import static org.mockito.Mockito.*;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;


/**
 * We mock a BufferedReader using mockito
 * @author Pello Xabier Altadill Izura
 * @greetz UuuuuuoooAaaaaUUUaa
 */
public class MockFile {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        // We create an instance of a false or mocked BufferedReader
        BufferedReader mockBufferedReader = mock(BufferedReader.class);
        
        // Then we stub readLine() function. It will return "747:John:Doe"
        when(mockBufferedReader.readLine()).thenReturn("747:John:Doe");
        
        // We establish that when mocked reader calls close an exception
        // will be thrown
        doThrow(new IOException()).when(mockBufferedReader).close();
        
        // Let's try
        System.out.println("First line: " + mockBufferedReader.readLine());
        
        // Now we close...
        mockBufferedReader.close();
        
        BufferedReader anotherMockReader;
        
        
    }

}
 

 


patrón DAO explicado por Peter

Las aplicaciones que gestionan datos de cualquier tipo necesitan acceder a repositorios de datos persistentes como las BBDD. Los datos no siempre tienen por qué estar en  una BD relacional a la que se accede por JDBC, es más, puede que la BD cambie o que incluso hay otro tipo de orígenes de datos como un LDAP. Con el objeto de separar la lógica de negocio con los detalles de acceso a los datos es habitual aplicar este patrón.

Todas las operaciones se hacen a través de una clase DAO que implementa todas las operaciones necesarias para gestionar determinados datos (CRUD + lo que haga falta). Esa clase DAO conoce los detalles del origen de los datos e incluso utiliza otra clase para gestionar el acceso a los mismos.

Para intercambiar información entre el DAO y la aplicación se utilizan objetos que representan los datos que se sacan del origen de datos, comúnmente suelen ser clases que representan una tabla de una BBDD.

Este es un ejemplo con una BBDD llamada ERP que contiene una tabla llamada Customer. 

Aplicando el patrón utilizaremos las siguientes clases:

  • Customer: representa los datos de la tabla y se utiliza para intercambiar información entre el programa y la clase DAO.
  • CustomerDAO: se encarga de todas las operaciones CRUD.
  • DataSource: se encarga de conseguir la conexión con el origen de datos.
  • Main: el programa que hace uso del CustomerDAO para interactuar con los datos persistentes.

Customer

 

/**
 * POJO class for Customer
 * @author Pello Altadill
 *
 */
public class Customer {
private int id;
private String name;
private String address;
 
/**
* @param id
* @param name
* @param address
*/
public Customer(int id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
 
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", address=" + address
+ "]";
}
 
 
/********** Getters/Setters ********************/
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
 
}
 

CustomerDAO

 

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
 
/**
 * 
 */
 
/**
 * @author Pello Altadill
 *
 */
public class CustomerDAO {
DataSource dataSource = new DataSource();
 
/**
* gets Customer data from DataBase
* @param customerId
* @return
*/
public Customer read (int customerId) {
Customer customer = null;
String name = "";
String address = "";
String sql = "select * from customer where id=" + customerId;
Connection connection = dataSource.getConnection();
try {
Statement statement =  connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
 
if (resultSet.next()) {
name = resultSet.getString("name");
address = resultSet.getString("address");
customer = new Customer(customerId, name, address);
} catch (Exception e) {
System.err.println("Exception: " +  sql + ". Error: " + e.getMessage());
return customer;
 
/**
* gets all Customer data from DataBase
* @return list of customers
*/
public List readAll () {
 
List customerList = new ArrayList();
int id = 0;
String name = "";
String address = "";
String sql = "select * from customer";
Connection connection = dataSource.getConnection();
try {
Statement statement =  connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
 
while (resultSet.next()) {
id = resultSet.getInt("id");
name = resultSet.getString("name");
address = resultSet.getString("address");
customerList.add(new Customer(id, name, address));
} catch (Exception e) {
System.err.println("Exception: " +  sql + ". Error: " + e.getMessage());
return customerList;
 
/**
* creates new Customer
* @param newCustomer
* @return
*/
public int create (Customer newCustomer) {
String sql = "insert into customer (name, address) values ('"+newCustomer.getName()+"','"+newCustomer.getAddress()+"')";
Connection connection = null;
Statement statement = null;
int result = 0;
 
try {
connection = dataSource.getConnection();
   statement = connection.createStatement();
   result = statement.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);
   
   // try to get generated key
   ResultSet rs = statement.getGeneratedKeys();
   if (rs.next()){
       result=rs.getInt(1);
   }
   
   System.out.println("[DataService] create> " + sql);
 
} catch (SQLException e) {
System.err.println("Exception: " +  sql + ". Error: " + e.getMessage());
} finally {
}
   return result;
}
 
/**
* updates customer information 
* @param customer
* @return
*/
public int update (Customer customer) {
String sql = "update customer set name='"+customer.getName()+"',address='"+customer.getAddress()+"' where id="+customer.getId();
Connection connection = null;
Statement statement = null;
int result = 0;
 
try {
connection = dataSource.getConnection();
   statement = connection.createStatement();
   result = statement.executeUpdate(sql);
   System.out.println("[DataService] update> " + sql);
} catch (SQLException e) {
System.err.println("Exception: " +  sql + ". Error: " + e.getMessage());
} finally {
}
   return result;
}
 
/**
* delete customer  
* @param customerId
* @return
*/
public int delete (int customerId) {
String sql = "delete from customer where id="+customerId;
Connection connection = null;
Statement statement = null;
int result = 0;
 
try {
connection = dataSource.getConnection();
   statement = connection.createStatement();
   result = statement.executeUpdate(sql);
   System.out.println("[DataService] delete> " + sql);
} catch (SQLException e) {
System.err.println("Exception: " +  sql + ". Error: " + e.getMessage());
} finally {
}
   return result;
}
 
}
 

DataSource

 

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
/**
 * This class provides access to a DataSource
 * and is used by DAO classes to get the Connection instance
 * @author Pello Altadill
 *
 */
public class DataSource {
 
private String dbUrl;
private String login;
private String password;
private String driver;
private Connection connection;
 
/**
* constructor for DataService
* opens connection to DataSource
* uses default dbUrl
*/
public DataSource () {
this.dbUrl = "jdbc:mysql://localhost:3306/erp";
this.login = "root";
this.password = "root";
this.driver = "com.mysql.jdbc.Driver";
openDataSource();
}
 
/**
* constructor for DataService
* @param dbUrl url to database
*/
public DataSource (String dbUrl, String login, String password, String driver) {
this.dbUrl = dbUrl;
this.login = login;
this.password = password;
this.driver = driver;
openDataSource();
}
 
/**
* opens connection to DataSource
*/
private void openDataSource() {
try {
Class.forName(this.driver);
connection = DriverManager.getConnection(this.dbUrl, this.login, this.password);
} catch (SQLException sqle) {
System.err.println("Connection error: " + sqle.getMessage());
} catch (Exception e) {
System.err.println("Connection error: " + e.getMessage());
}
}
 
/**
* returns current opened connection to DataSource
* @return Connection instance
*/
public Connection getConnection () {
return connection;
}
 
/**
* closes DataSource connection
*/
public void close () {
try {
connection.close();
} catch (SQLException sqle) {
System.err.println("Connection error: " + sqle.getMessage());
} catch (Exception e) {
System.err.println("Connection error: " + e.getMessage());
}
}
 
 
}
 

Main

import java.util.Scanner;

 
 
/**
 * @author luser
 *
 */
public class Main {
 
/**
* @param args
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
CustomerDAO customerDAO = new CustomerDAO();
 
// TODO Auto-generated method stub
int id = 0;
String name = "";
String address = "";
 
// CREATE
System.out.println("Insert new Name");
name = scanner.nextLine();
System.out.println("Insert new Adress");
address = scanner.nextLine();
 
Customer customer = new Customer(0, name, address);
int newId = customerDAO.create(customer);
 
customer.setId(newId);
 
System.out.println("Customer data: " + customer.toString());
 
// UPDATE DATA
System.out.println("Insert new Name");
name = scanner.nextLine();
System.out.println("Insert new Adress");
address = scanner.nextLine();
 
customer.setName(name);
customer.setAddress(address);
customerDAO.update(customer);
 
// REMOVE
customerDAO.delete(customer.getId());
 
}
 
}
 

El DAO pattern de la mano de Oracle

Diagrama del patrón DAO

 

LaOca - Goose Game

Código en Google code
Con la intención de servir como base para juegos de tablero más complejos esta sería una implementación del juego de la OCA en java. Este juego es tan sumamente malo que todo lo juega la propia máquina, no necesita intervención humana alguna. Así que un programa principal crea la instancia de juego, añade jugadores y los pone a tirar dados y a moverse. Al llegar todos a la meta el juego termina.
 
El tablero es más simple, no contiene las 63 casillas estándar, pero lo mismo da. Está hecho con un array y las casillas especiales tienen un valor de salto, que puede ser hacia adelante o hacia atrás.
 
Faltaría meter lo del pozo, que me suena que era varios turnos sin jugar.
 

Main

 
Clase principal
 
 
 
package info.pello.games.oca;
 
/** 
 * La Oca - Game of Goose 
 * This is an implementation of a really dumb game where 
 * players just roll dices and move on, without any possible 
 * choice. So It's a perfect game to for a computer to resolve, 
 * because no human intervention is really needed. 
 * First coded for educational purposes, then just for fun 
 * and finally... I don't know. 
 * @author Pello Xabierl Altadill 
 * @greets Movistar 
 */
public class Main {
 
        /** 
         * I try to keep the main function simple, just an instance 
         * of Game class, initialization, a game loop and result. 
         * @param args 
         */
        public static void main(String[] args) {
                Game game = new Game();
                
                game.addPlayer("Pello");
                game.addPlayer("June");
                game.addPlayer("Josu");
                game.addPlayer("COM");
                
                do {
                        System.out.println(game.boardState());
                        System.out.println(game.moveCurrent());
                        game.nextTurn();
                } while (game.notFinished());
 
                System.out.println("\nLast state:");
                System.out.println(game.boardState());
                System.out.println(game.gameResult());
 
        }
 
}
 

JDBC en java

Este es un churro resumen de las cuatro cosas básicas que se hacen con el JDBC, en concreto:

-Las operaciones CRUD (en jdbc el select de una forma el resto de otra)

-El tema de las PreparedStatement, que es la forma correcta de hacer las cosas.

-El tema de sacar el último campo clave generado. En el caso de autonuméricos nos interesa saberlo en muchas ocasiones y la cosa tiene su aquel en java.

 

import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
 
 
/**
 * churro con las cosas básicas de JDBC
 * @author pello_altadill
 *
 */
public class Main {
 
 
/**
* @param args
*/
public static void main(String[] args) {
  try {
 Class.forName("com.mysql.jdbc.Driver");
 Connection conn =
 DriverManager.getConnection("jdbc:mysql://localhost/erp","root","");
 Statement stat = conn.createStatement();
 ResultSet resultset = stat.executeQuery("select * from customer;");
 
   while (resultset.next()) {
     System.out.println("id = " + resultset.getString("id"));
     System.out.println("name = " + resultset.getString("name"));
   }
   
 // INSERT
 String insertQuery = 
 "insert into customer (name,address) values('Sauron','Mordor')";
 int result = stat.executeUpdate(insertQuery);
 
 // INSERT RECUPERANDO LA ÚLTIMA CLAVE
 insertQuery = "insert into customer (name,address) values('Melkor','Angband')";
 
 result = stat.executeUpdate(insertQuery,Statement.RETURN_GENERATED_KEYS);
   
   // Sacamos la clave
   ResultSet rs = stat.getGeneratedKeys();
   if (rs.next()){
       result=rs.getInt(1);
   }
 
 // DELETE
 int id = 4;
 String deleteQuery = "delete from customer where id=" + id;
 result = stat.executeUpdate(deleteQuery);
 
 // UPDATE
 String who = "Saruman";
 String updateQuery = 
"update customer set address='The Shire' where name='"+who+"'";
 result = stat.executeUpdate(updateQuery);
 
 // PREPARED STATEMENT
 String insertSQL = 
"insert into customer (name,address) values (?, ?)";
 PreparedStatement prep = conn.prepareStatement(insertSQL);
 
   prep.setString(1, "Eomer");
   prep.setString(2, "Rohan");
   prep.addBatch();
 
   prep.setString(1, "Sam");
   prep.setString(2, "The Shire");
   prep.addBatch();
 
   prep.executeBatch();
   resultset.close();
   conn.close();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
 
}
 

JavaHammer

 

JavaHammer es una versión simplificada del juego BattleMasters de MB. El BattleMasters era una versión simplificada de Warhammer en la que  dos ejércitos se enfre ellos hasta la aniquilación de uno de los dos.

 

Repositorio subversion con el código.

Cada ejercito está formado por distintas unidades. Cada unidad tiene un nombre, un valor de ataque, un valor de defensa, un valor de movimiento que suele ser 1, un rango de ataque que suele ser 1 y los puntos de vida que suelen ser tres.

 

Hay varias clases de unidades: infantería, arqueros y caballería.

 

El escenario es un mapa de 10x10 terrenos. En cada terreno solo cabe una unidad de un ejercito cada vez y tienen que tener un nombre ominoso tipo "llanura del mal innominado"

 

En el juego debe haber un inicio en el que se genera el mapa de forma aleatoria.

 

El programa está lleno de CodeSmells debe mejorarse un montón, aunque en todo momento se ha intentado desacoplar, cohersionar, etc...

 

Este es el aspecto de JavaHammer en consola.

 

-=-=-=-=-=-=-=-[ JavaHammer ]-=-=-=-=-=-=-=-
 
   0    1    2    3    4    5    6    7    8    9  
0[   ][2B1][2I1][2B2][2I2][2B3][2I3][2C1][2C2][   ]
1[   ][   ][   ][   ][   ][   ][   ][   ][   ][   ]
2[   ][   ][   ][   ][   ][   ][   ][   ][   ][   ]
3[   ][   ][   ][   ][   ][   ][   ][   ][   ][   ]
4[   ][   ][   ][   ][   ][   ][   ][   ][   ][   ]
5[   ][   ][   ][   ][   ][   ][   ][   ][   ][   ]
6[   ][   ][   ][   ][   ][   ][   ][   ][   ][   ]
7[   ][   ][   ][   ][   ][   ][   ][   ][   ][   ]
8[   ][   ][   ][   ][   ][   ][   ][   ][   ][   ]
9[   ][1B1][1I1][1B2][1I2][1B3][1I3][1C1][1C2][   ]
   0    1    2    3    4    5    6    7    8    9  
Demons's turn 
Please choose:
m. Move
a. Attack
s. Show Map
t. Show Army Status
p. Pass
Option: 
 

Palíndromo 

El clásico ejemplo de palíndromo, en este caso para probar la palabra Shared en los métodos de una clase, que en definitiv equivale al static de java.

Se usa el palíndromo para String y para Enteros.

 

Public Class Palindromo
 
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="cadena"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function esPalindromo(ByVal cadena As String) As Boolean
 
        Dim inversa As String = Microsoft.VisualBasic.StrReverse(cadena)
 
        For I As Integer = 0 To cadena.Length - 1
            If cadena.ElementAt(I) <> inversa.ElementAt(I) Then
                Return False
            End If
        Next
        Return True
 
    End Function
 
    ''' <summary>
    ''' esPalindromo con enteros, convierte el entero a cadena y reutiliza el 
    ''' método que espera Strings
    ''' </summary>
    ''' <param name="cadena"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function esPalindromo(ByVal cadena As Integer) As Boolean
        Return esPalindromo(cadena.ToString)
    End Function
 
End Class

Banner es el clásico programa de unix para sacar por consola un texto en tamaño grande. Había planteado esto y me mandaron una soluciones efectivas pero algo choriceras. Yo planteo esta. Lo hago pensando orientado a objetos, por tanto divido el problema en cosas, no en funciones. Las cosas que salen son: caracteres, pantalla, y alguien que escribe. En java me quedarían 4 clases, una añadida para hacer el main.

Letter

Este es un hashtable que contiene las letras en un hashtable. No he metido todas, porque al igual que a Carlos esto es algo denigrante.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.cuatrovientos.banner;

import java.util.Hashtable;

/**
 * Letters
 * singleton hashtable that holds all letters
 * @author Pello Xabier
 * note: from now on I'll not forget the private constructor, I swear ;)
 */
public class Letters extends Hashtable<String, String[][]>{

    private static Letters letters = null;
    private static final int LETTER_WIDTH = 4;
    private static final int LETTER_HEIGHT = 5;
    
    /**
     * private constructor
     */
    private Letters () {
        initialize();
    }

    /**
     * getLetters
     * @return
     */
    public static Letters getLetters () {
        if (letters == null) {
            letters = new Letters();
        }

        return letters;
    }

    /**
     * initialize
     * puts letters into the hashtable
     * Note: I'll NOT put all letters, It's too late for this,
     * and I know that this font is horrid, but gimme a break.
     */
    private void initialize () {
        this.put("A",new String[][]{{"A","A","A","A"},
                                    {"A"," "," ","A"},
                                    {"A","A","A","A"},
                                    {"A"," "," ","A"},
                                    {"A"," "," ","A"}});
        this.put("B",new String[][]{{"B","B","B","B"},
                                    {"B"," "," ","B"},
                                    {"B","B","B"," "},
                                    {"B"," "," ","B"},
                                    {"B","B","B","B"}});
        this.put("C",new String[][]{{"C","C","C","C"},
                                    {"C"," "," "," "},
                                    {"C"," "," "," "},
                                    {"C"," "," "," "},
                                    {"C","C","C","C"}});
        this.put("D",new String[][]{{"D","D","D"," "},
                                    {"D"," "," ","D"},
                                    {"D"," "," ","D"},
                                    {"D"," "," ","D"},
                                    {"D","D","D"," "}});
        this.put("E",new String[][]{{"E","E","E","E"},
                                    {"E"," "," "," "},
                                    {"E","E","E"," "},
                                    {"E"," "," "," "},
                                    {"E","E","E","E"}});
    }


    /**
     * getHeight
     * @return hegith of letters
     */
    public int getHeight () {
        return LETTER_HEIGHT;
    }

    /**
     *  getWidth
     * @return width of letters
     */
    public int getWidth () {
        return LETTER_WIDTH;
    }

}
 

Screen

Representa la pantalla, es una especie de lienzo en forma de array de Strings. La función fill es la que nos permite pintar un caracter en unas coordenadas. Y finalmente la función draw vuelca todo el lienzo en pantalla.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.cuatrovientos.banner;

/**
 * Screen
 * The class where we paint the Letters
 * @author Pello Xabier
 * note: from now on I'll not forget the private constructor, I swear ;)
 */
public class Screen {
    private final static int WIDTH = 80;
    private final static int HEIGHT = 24;
    private final static String WHITESPACE = " ";
    private final static char NEWLINE = '\n';
    private String[][] canvas = new String[HEIGHT][WIDTH];
    private static Screen theScreen = null;

    // private constructor
    private Screen () { clear(); }

    /**
     * clears the screen
     */
    private void clear () {
        for (int h = 0;h< HEIGHT; h++)
            for (int w=0;w<WIDTH; w++)
                canvas[h][w] = WHITESPACE;
    }

    /**
     * getScreen
     * @return the one and only screen instance
     */
    public static Screen getScreen() {
        if (theScreen == null) {
            theScreen = new Screen();
        }

        return theScreen;
    }

    /**
     * fill
     * fills  the screen with a matrix at given coords
     * @param what
     * @param x
     * @param y
     */
    public void fill (String[][] what, int x, int y) {

        if (boundsOk(x,y)) {
            int i = 0, j = 0;
            //go on and fill the canvas
            for (int h = y;h< y+what.length; h++) {
                for (int w=x;w<x+what[0].length; w++)
                    canvas[h][w] = what[i][j++];
                i++;j=0;
            }//for

        }//if
    }

    /**
     * draw
     * paints contents on console
     */
    public void draw () {
        for (int h = 0;h< HEIGHT; h++) {
            for (int w=0;w<WIDTH; w++)
                System.out.print(canvas[h][w]);
            System.out.print(NEWLINE);
        }
    }

    /**
     * boundsOk
     * tell us if given coords are inside Screen margins
     * @param x
     * @param y
     * @return true if coords are ok.
     */
    public boolean boundsOk (int x, int y) {
        return (y >= 0 && y < HEIGHT && x >= 0 && x < WIDTH);
    }
}
 

Writer

Usando la pantalla va escribiendo caracteres y avanzando el cursor.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.cuatrovientos.banner;

/**
 * Writer
 * Gets the Screen and writes a word on It.
 * @author Pello Xabier
 */
public class Writer {

    private int initialX;
    private int initialY;

    /**
     * Writer
     * constructor
     * initializes positions at 0
     */
    public Writer () {
        initialX = 0;
        initialY = 0;
    }


    /**
     * Writer
     * constructor
     * initializes positions at x,y
     */
    public Writer (int x , int y) {
        if (Screen.getScreen().boundsOk(x, y)) {
            initialX = x;
            initialY = y;
        } else { // bajeril stylo
            initialX = initialY = 0;
        }
    }

    /**
     * writes the string
     * @param messageToWrite
     */
    public void write (String messageToWrite) {
        int x = initialX;
        int y = initialY;

        if (messageDoesNotFitScreen(messageToWrite)) {
            System.out.println("Sorry. Message does not fit the screen");
            return;
        }

        // It's ok, we took each letter, we write on the screen and we move the cursor forward
        for (int i = 0; i< messageToWrite.length();i++) {
            // TODO next line: choose btw coolness and refactoring
            Screen.getScreen().fill(Letters.getLetters().get(messageToWrite.substring(i, i+1).toUpperCase()), x, y);
            x = x + Letters.getLetters().getWidth() + 1;
        }
        
        // Finally, we draw the screen
        Screen.getScreen().draw();
    }


    /**
     * messageDoesNotFitScreen
     * @param message
     * @return true if message is longer than screen width
     */
    private boolean messageDoesNotFitScreen (String message) {
        return (((message.length()+1) * Letters.getLetters().getWidth()) > 80);
    }
}
 

Main

Instancia writer y escribe,  no más.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.cuatrovientos.banner;

/**
 *
 * @author pello xabier
 * @greetz 1º DAM @cuatrovientos
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        Writer writer = new Writer(5,7);

        writer.write("ABC");
    }

}
 


 

Seguimos con Visual Basic .NET, en este caso un programilla en el que el usuario da una base y una altura y según lo que elija se calcula el área de un triángulo o el perímetro de un rectángulo. Aquí se ve un pantallazo:
 
 
Vamos, no es nada del otro jueves que digamos.
 
La clase Triángulo
 
Esta es una clase que representa un triángulo y tiene un método para calcular el área
 
Public Class Triangulo
    Private _base As Double
    Private _altura As Double
 
    Public Property base As Double
        Get
            Return _base
        End Get
        Set(ByVal value As Double)
            _base = value
        End Set
    End Property
 
    Public Property altura As Double
        Get
            Return _altura
        End Get
        Set(ByVal value As Double)
            _altura = value
        End Set
    End Property
 
    '''
    ''' Constructor de la clase
    '''
    '''
    '''
    '''
    Public Sub New(ByVal base As Double, ByVal altura As Double)
        Me.base = base
        Me.altura = altura
 
    End Sub
 
    '''
    ''' Area, calcula el área de un triángulo
    '''
    ''' Double
    '''
    Public Function Area() As Double
        Return ((_base * _altura) / 2)
    End Function
 
End Class
 
La clase Rectángulo
 
Esta es una clase que representa un rectángulo y tiene un método para calcular el área y el perímetro
 
Public Class Rectangulo
    Private _base As Double
    Private _altura As Double
 
    Public Property base As Double
        Get
            Return _base
        End Get
        Set(ByVal value As Double)
            _base = value
        End Set
    End Property
 
    Public Property altura As Double
        Get
            Return _altura
        End Get
        Set(ByVal value As Double)
            _altura = value
        End Set
    End Property
 
    Public Sub New(ByVal base As Double, ByVal altura As Double)
        Me.base = base
        Me.altura = altura
 
    End Sub
 
    '''
    ''' Area
    '''
    ''' Double
    '''
    Public Function Area() As Double
        Return _base * _altura
    End Function
 
    '''
    ''' Perimetro
    '''
    ''' Double
    '''
    Public Function Perimetro() As Double
        Return _base * 2 + _altura * 2
    End Function
End Class
 
 
El interfaz
 
El interefaz de usuario no es más que una clase Form que básicamente atiende los eventos de los botones y los radiobuttons.
 
Public Class Form1
 
    Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rbRectangulo.CheckedChanged
        GroupBox1.Text = "Rectángulo"
        lblArea.Visible = False
        lblTxtArea.Visible = False
        lblTxtArea.Text = ""
 
        txtBase.Focus()
        lblPerimetro.Visible = True
        lblTxtPerimetro.Visible = True
 
    End Sub
 
    Private Sub RadioButton2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rbTriangulo.CheckedChanged
        GroupBox1.Text = "Triángulo"
        lblPerimetro.Visible = False
        lblTxtPerimetro.Visible = False
        lblTxtPerimetro.Text = ""
 
        lblArea.Visible = True
        lblTxtArea.Visible = True
        txtAltura.Focus()
    End Sub
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Close()
 
    End Sub
 
    Private Sub btnResultados_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnResultados.Click
        Dim errores As Boolean = False
        Dim base As Double = 0
        Dim altura As Double = 0
 
 
        If Not IsNumeric(txtAltura.Text) Then
            errores = True
            txtAltura.Focus()
        End If
 
        If Not IsNumeric(txtBase.Text) Then
            errores = True
            txtBase.Focus()
        End If
 
        If errores Then
            MsgBox("Error datos no numéricos")
        Else
 
            base = Double.Parse(txtBase.Text)
            altura = Double.Parse(txtAltura.Text)
 
            If rbRectangulo.Checked Then
                Dim miRectangulo As Rectangulo = New Rectangulo(base, altura)
                lblTxtPerimetro.Text = miRectangulo.Perimetro
            Else
                Dim miTriangulo As Triangulo = New Triangulo(base, altura)
                lblTxtArea.Text = miTriangulo.Area
            End If
        End If
 
    End Sub
End Class

Guste o no Visual Basic da de comer y no se puede relegar. Es inevitable

Este el el clásico ejemplo de Visual Basic, un programa para resolver una ecuación de 2º grado. Está hecho con un par de clases, una se ocupa de la ecuación y la otra del interfaz de usuario.

Image Hosted by ImageShack.us
 

Clase Ecuación

Esta sería la clase que representa la ecuación, y tiene unos métodos para comprobar si tiene solución y luego para resolver la ecuación.

 

'Clase que representa una ecuación de 2º Grado
Public Class Ecuacion
    Private _A As Double
    Private _B As Double
    Private _C As Double
 
 
    Public Property A As Double
        Get
            Return _A
        End Get
        Set(ByVal value As Double)
            _A = value
        End Set
    End Property
 
    Public Property B As Double
        Get
            Return _B
        End Get
        Set(ByVal value As Double)
            _B = value
        End Set
    End Property
 
    Public Property C As Double
        Get
            Return _C
        End Get
        Set(ByVal value As Double)
            _C = value
        End Set
    End Property
 
    '''
    ''' Comprueba si parte de la ecuación
    ''' devuelve negativo
    '''
    ''' Boolean
    '''
 
    Public Function TieneSolucion() As Boolean
        If (_B ^ 2 - 4 * _A * _C) < 0 Then
            Return False
        Else
            Return True
        End If
    End Function
 
    '''
    ''' Resuelve la ecuación
    '''
    ''' Double
    '''
    Public Function X1() As Double
        Return (-B + Math.Sqrt((_B ^ 2 - 4 * _A * _C))) / (2 * A)
    End Function
 
    '''
    ''' Resuelve la ecuación
    '''
    ''' Double
    '''
    Public Function X2() As Double
        Return (-B - Math.Sqrt((_B ^ 2 - 4 * _A * _C))) / (2 * A)
    End Function
 
End Class
 
 
El formulario
El formulario es otra clase, todo el mogollón se produce al hacer click en el botón, y he separado código en algunas funciones para que no esté todo apelotonado

subscribe via RSS