Antes de nada comentar que esto es un ejercicio de «un ejemplo claro» de la necesidad de aplicar OOP a tu proyecto. Es el ejercicio que todos los «profes» entregan después de haber explicado toda la teoría. Si no sabes que es eso de la OOP, vuelve después de visitar los enlaces que te propongo.

Si ya conoces la teoría, sabes como hacer clases, pero aún piensas que te sirven para poco, sigue leyendo.

Este ejercicio, es un ejemplo para toda aquella gente que comprende los conceptos básicos de OOP en Actionscript 2.0, en cambio, sus avances por la misma no llegan más lejos que la concepción de una clase como una clásica estructura (struct) o un conjunto de funciones estáticas comunes, y que no aprovecha o no ha visualizado claramente que casos son los imprescindibles para el desarrollo de un modelo orientado a objetos en Actionscript 2.0
En él se entiende la Programación Orientada a Objetos como una posibilidad de definir arquitecturas escalables en nuestra aplicacion, pudiendo añadir nuevas clases para soportar la fase de mantenimiento de un proyecto sin necesidad de desarrollar profundos cambios en la aplicación, reescribiendo y repitiendo código.

Transcrito a Actionscript 2.0 se basa en uno de los primeros ejercicios de una asignatura de Java , y con él profundizo la idea de herencia como un método de dotar a las clases heredadas de la capacidad de invocar métodos de sus padres. Además, se juega con los atributos miembros de instancia y atributos estáticos, así como los constructores y las llamadas a los mismos.

A continuación describo el enunciado del ejercicio:

Disponemos de una aplicación remota, que se encarga de manejar todos los equipos informáticos de una universidad (encendido, apagado, reinicio…), ya sean pcs, routers o switches.

Cada uno de los equipos de nuestro aula, viene referenciado por su Clase correspondiente:

[as]class Pc {
//implementación
}
class Switch{
//implementación
}
class Router{
//implementación
} [/as]

 

La implementación del método «apagar» de los equipos es la siguiente:

[as]public function apagar():Void{
trace(«apagando…»);
} [/as]

Diseñar un modelo de clases óptimo y escalable (se puedan añadir nuevos tipos de máquinas) en Actionscript 2.0 que permita:

  • apagar manualmente alguno de los pcs de la sala,
  • apagar todos ellos mediante la invocación de un sólo método.
  • monitorizar el número de equipos instanciados en la aplicación

 

Cualquier programador estructurado puede temblar ante proyectos de este tipo. Hoy son sólo tres tipos, pero mañana pueden ser modems, servidores de almacenamiento, web, de bases de datos, de aplicaciones, de correo… monitorizadores, equipos, proyectores, portátiles… :S

la lista es enorme y los comportamientos muy muy parecidos, es decir, muchas implementaciones, algunas iguales, y otras muy distintas. Se puede trabajar con funciones genéricas, pero la lista de switch-case puede llegar a ser enorme.

Sin embargo, las implementaciones de las clases heredadas que tienen el patrón común es tan simple como:

para resolver los puntos b y c:

  • apagar todos ellos mediante la invocación de un sólo método.
  • monitorizar el número de equipos instanciados en la aplicación

[as]class Switch extends Pool{
}
class Pc extends Pool{
}
class Router extends Pool{
}[/as]

 

mientras tanto, nuestra clase Pool es la que contiene toda la implementación:

[as]
/**
* Clase pool solución posible al ejercicio de un ejemplo de herencia.
* se puede tratar como una superclase abstracta que permite extender los métodos de la misma a sus hijas
* @author Alejandro Sánchez Marcos
*/
class Pool {
private static var numMaquinas:Number = 0;
private static var vMaquinas = new Array();
public var queMaquina:Number;
function Pool(){
numMaquinas++;
queMaquina=numMaquinas;
vMaquinas.push(this);
}

/**
* método que apaga una máquina
*/
public function apaga():Void {
trace(«[user] apagando máquina «+queMaquina);
}
private function apagar():Void {
trace(«[system] apagando máquina»+queMaquina);
}
/**
* método estático que permite apagar todas las máquinas del pool
*/
public static function apagarTodos():Void{
//para cada una de las máquinas de nuestro pool…
for (var i=0; i<vmaquinas .length; i++){
var mimaquina = vMaquinas[i];
//apagamos…
mimaquina.apagar();
}
}
}
[/as]

 

Pero ¿qué pasa con el punto 1?

  • apagar manualmente alguno de los pcs de la sala,

existen particularidades, como la necesidad de apagar un pc. Para eso, podemos definir nuestra clase pc para que se aproveche sólo de lo que le hace falta:

[as]
/**
* Clase que representa un pc. solución posible al
* ejercicio de un ejemplo de herencia.
* @author Alejandro Sánchez Marcos alex_en_electroduendes.com
*/

class Pc extends Pool {
private static var numPcsEncendidos:Number = 0;

/**
* Constructor de la clase Pc.
* Sólo puede declararse un constructor.
* Invoca por defecto al constructor de su superclase
* No está permitido sobreescribir. sólo añade
* implementación
*/
public function Pc() {
trace(«[Pc] nuevo pc en el sistema»);
numPcsEncendidos++;
super();
}

/**
* Método apaga de pc. En este caso,
* sí se permite la sobreescritura * y gracias al puntero super, la sobrecarga.
*/
public function apaga():Void {
trace(«[Pc] apagando pc»);
super.apaga(); //necesario si deseamos extender
//las propiedades del método apagar
numPcsEncendidos–;
}
public static function printNumPcs():Void {
trace(«[Pc] Total pcs encendidos en sistema: «+numPcsEncendidos);
}
} [/as]

 

Introduciendo el concepto de interfaz, es posible que en cualquier ámbito del proyecto sea necesario recibir una máquina en algun método de alguna otra clase y se tenga que implementar varios métodos para cada una de los tipos de máquina. Para ese cometido además de otros, podemos recibir nuestro switch, servidor, o pc, como una interfaz de tipo «máquina», ya que una interfaz se concibe como un tipo de dato capaz de albergar y manipular clases que implementan la misma.

[as]interface PoolInterface
{
function apaga () : Void;
};[/as]

[as]class Pool implements PoolInterface
{
function apaga () : Void{}
//….
}[/as]

En resúmen, dominando este ejemplo, aprenderemos conceptos tan básicos como:

  • Herencia de métodos y constructores. (llamada al constructor de pool)
  • Ámbito de los métodos. (Constructor de Pool es privado)
  • Uso de métodos estáticos y su relación con las distintas instancias (atributo numPcsEncendidos)
  • Posibilidad de definir arquitecturas escalables (mañana podremos introducir una clase Servidor fácilmente)
  • Encapsulación; varias instancias de distintas máquinas se comportan de la misma manera y no importa su tipo (todas tienen un método apagar)

Espero que hos haya resultado útil. Para cualquier sugerencia, error, mejora… alex_en_electroduendes.com.

Y por supuesto, como última recomendación, usa los foros. En este hilo, Joan y yo hablamos del tema.