Un poco de Patrones de Diseño GoF (Gang of Four)

El objetivo principal de los patrones es facilitar la reutilización de diseños y arquitecturas software que han tenido éxito capturando la experiencia y haciéndola accesible a los no expertos.

Dentro de los patrones clásicos tenemos los GoF (Gang of Four),estudiados por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides en su mítico libro Design Patterns se contemplan 3 tipos de patrones:

· Patrones de creación: tratan de la inicialización y configuración de clases y objetos

· Patrones estructurales: Tratan de desacoplar interfaz e implementación de clases y objetos

· Patrones de comportamiento tratan de las interacciones dinámicas entre sociedades de clases y objetos

Y dentro de cada grupo tenemos:

Patrones de creación

· Abstract Factory. Proporciona una interfaz para crear familias de objetos o que dependen entre sí, sin especificar sus clases concretas.

· Builder. Separa la construcción de un objeto complejo de su representación, de forma que el mismo proceso de construcción pueda crear diferentes representaciones.

· Factory Method. Define una interfaz para crear un objeto, pero deja que sean las subclases quienes decidan qué clase instanciar. Permite que una clase delegue en sus subclases la creación de objetos.

· Prototype. Especifica los tipos de objetos a crear por medio de una instancia prototípica, y crear nuevos objetos copiando este prototipo.

· Singleton. Garantiza que una clase sólo tenga una instancia, y proporciona un punto de acceso global a ella.

Patrones estructurales

· Adapter. Convierte la interfaz de una clase en otra distinta que es la que esperan los clientes. Permiten que cooperen clases que de otra manera no podrían por tener interfaces incompatibles.

· Bridge. Desvincula una abstracción de su implementación, de manera que ambas puedan variar de forma independiente.

· Composite. Combina objetos en estructuras de árbol para representar jerarquías de parte-todo. Permite que los clientes traten de manera uniforme a los objetos individuales y a los compuestos.

· Decorator. Añade dinámicamente nuevas responsabilidades a un objeto, proporcionando una alternativa flexible a la herencia para extender la funcionalidad.

· Facade. Proporciona una interfaz unificada para un conjunto de interfaces de un subsistema. Define una interfaz de alto nivel que hace que el subsistema se más fácil de usar.

· Flyweight. Usa el compartimiento para permitir un gran número de objetos de grano fino de forma eficiente.

· Proxy. Proporciona un sustituto o representante de otro objeto para controlar el acceso a éste.

Patrones de comportamiento

· Chain of Responsibility. Evita acoplar el emisor de una petición a su receptor, al dar a más de un objeto la posibilidad de responder a la petición. Crea una cadena con los objetos receptores y pasa la petición a través de la cadena hasta que esta sea tratada por algún objeto.

· Command. Encapsula una petición en un objeto, permitiendo así parametrizar a los clientes con distintas peticiones, encolar o llevar un registro de las peticiones y poder deshacer la operaciones.

· Interpreter. Dado un lenguaje, define una representación de su gramática junto con un intérprete que usa dicha representación para interpretar las sentencias del lenguaje.

· Iterator. Proporciona un modo de acceder secuencialmente a los elementos de un objeto agregado sin exponer su representación interna.

· Mediator. Define un objeto que encapsula cómo interactúan un conjunto de objetos. Promueve un bajo acoplamiento al evitar que los objetos se refieran unos a otros explícitamente, y permite variar la interacción entre ellos de forma independiente.

· Memento. Representa y externaliza el estado interno de un objeto sin violar la encapsulación, de forma que éste puede volver a dicho estado más tarde.

· Observer. Define una dependencia de uno-a-muchos entre objetos, de forma que cuando un objeto cambia de estado se notifica y actualizan automáticamente todos los objetos.

· State. Permite que un objeto modifique su comportamiento cada vez que cambia su estado interno. Parecerá que cambia la clase del objeto.

· Strategy. Define una familia de algoritmos, encapsula uno de ellos y los hace intercambiables. Permite que un algoritmo varíe independientemente de los clientes que lo usan.

· Template Method. Define en una operación el esqueleto de un algoritmo, delegando en las subclases algunos de sus pasos. Permite que las subclases redefinan ciertos pasos del algoritmo sin cambiar su estructura.

· Visitor. Representa una operación sobre los elementos de una estructura de objetos. Permite definir una nueva operación sin cambiar las clases de los elementos sobre los que opera.

Si de este resumen os interesa este tema y os da pereza leer en inglés os recomiendo esta presentación:

En este otro PDF se hace un estudio de estos mismos patrones mostrando ejemplos con código.

Por ejemplo para el patrón Facade:

El problema:

 

La solución:

 

Y otra más de Visores JSON

Y para seguir con los posts de Visores JSON este otro formateador: JsonFormatter.

Y aquí el código de la versión simple de este visor:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<script>

// we need tabs as spaces and not CSS magin-left

// in order to ratain format when coping and pasing the code

window.SINGLE_TAB = " ";

window.ImgCollapsed = "Collapsed.gif";

window.ImgExpanded = "Expanded.gif";

window.QuoteKeys = true;

function $id(id){ return document.getElementById(id); }

function IsArray(obj) {

return obj &&

typeof obj === ‘object’ &&

typeof obj.length === ‘number’ &&

!(obj.propertyIsEnumerable(‘length’));

}

function Process(){

SetTab();

window.IsCollapsible = true;

var json = $id("RawJson").value;

var html = "";

try{

if(json == "") json = """";

var obj = eval("["+json+"]");

html = ProcessObject(obj[0], 0, false, false, false);

$id("Canvas").innerHTML = "<PRE class=’CodeContainer’>"+html+"</PRE>";

}catch(e){

alert("JSON is not well formated:n"+e.message);

$id("Canvas").innerHTML = "";

}

}

window._dateObj = new Date();

window._regexpObj = new RegExp();

function ProcessObject(obj, indent, addComma, isArray, isPropertyContent){

var html = "";

var comma = (addComma) ? "<span class=’Comma’>,</span> " : "";

var type = typeof obj;

var clpsHtml ="";

if(IsArray(obj)){

if(obj.length == 0){

html += GetRow(indent, "<span class=’ArrayBrace’>[ ]</span>"+comma, isPropertyContent);

}else{

clpsHtml = window.IsCollapsible ? "<span><img src=""+window.ImgExpanded+"" onClick="ExpImgClicked(this)" /></span><span class=’collapsible’>" : "";

html += GetRow(indent, "<span class=’ArrayBrace’>[</span>"+clpsHtml, isPropertyContent);

for(var i = 0; i < obj.length; i++){

html += ProcessObject(obj[i], indent + 1, i < (obj.length – 1), true, false);

}

clpsHtml = window.IsCollapsible ? "</span>" : "";

html += GetRow(indent, clpsHtml+"<span class=’ArrayBrace’>]</span>"+comma);

}

}else if(type == ‘object’){

if (obj == null){

html += FormatLiteral("null", "", comma, indent, isArray, "Null");

}else if (obj.constructor == window._dateObj.constructor) {

html += FormatLiteral("new Date(" + obj.getTime() + ") /*" + obj.toLocaleString()+"*/", "", comma, indent, isArray, "Date");

}else if (obj.constructor == window._regexpObj.constructor) {

html += FormatLiteral("new RegExp(" + obj + ")", "", comma, indent, isArray, "RegExp");

}else{

var numProps = 0;

for(var prop in obj) numProps++;

if(numProps == 0){

html += GetRow(indent, "<span class=’ObjectBrace’>{ }</span>"+comma, isPropertyContent);

}else{

clpsHtml = window.IsCollapsible ? "<span><img src=""+window.ImgExpanded+"" onClick="ExpImgClicked(this)" /></span><span class=’collapsible’>" : "";

html += GetRow(indent, "<span class=’ObjectBrace’>{</span>"+clpsHtml, isPropertyContent);

var j = 0;

for(var prop in obj){

var quote = window.QuoteKeys ? """ : "";

html += GetRow(indent + 1, "<span class=’PropertyName’>"+quote+prop+quote+"</span>: "+ProcessObject(obj[prop], indent + 1, ++j < numProps, false, true));

}

clpsHtml = window.IsCollapsible ? "</span>" : "";

html += GetRow(indent, clpsHtml+"<span class=’ObjectBrace’>}</span>"+comma);

}

}

}else if(type == ‘number’){

html += FormatLiteral(obj, "", comma, indent, isArray, "Number");

}else if(type == ‘boolean’){

html += FormatLiteral(obj, "", comma, indent, isArray, "Boolean");

}else if(type == ‘function’){

if (obj.constructor == window._regexpObj.constructor) {

html += FormatLiteral("new RegExp(" + obj + ")", "", comma, indent, isArray, "RegExp");

}else{

obj = FormatFunction(indent, obj);

html += FormatLiteral(obj, "", comma, indent, isArray, "Function");

}

}else if(type == ‘undefined’){

html += FormatLiteral("undefined", "", comma, indent, isArray, "Null");

}else{

html += FormatLiteral(obj.toString().split("\").join("\\").split(‘"’).join(‘\"’), """, comma, indent, isArray, "String");

}

return html;

}

function FormatLiteral(literal, quote, comma, indent, isArray, style){

if(typeof literal == ‘string’)

literal = literal.split("<").join("&lt;").split(">").join("&gt;");

var str = "<span class=’"+style+"’>"+quote+literal+quote+comma+"</span>";

if(isArray) str = GetRow(indent, str);

return str;

}

function FormatFunction(indent, obj){

var tabs = "";

for(var i = 0; i < indent; i++) tabs += window.TAB;

var funcStrArray = obj.toString().split("n");

var str = "";

for(var i = 0; i < funcStrArray.length; i++){

str += ((i==0)?"":tabs) + funcStrArray[i] + "n";

}

return str;

}

function GetRow(indent, data, isPropertyContent){

var tabs = "";

for(var i = 0; i < indent && !isPropertyContent; i++) tabs += window.TAB;

if(data != null && data.length > 0 && data.charAt(data.length-1) != "n")

data = data+"n";

return tabs+data;

}

function TraverseChildren(element, func, depth){

for(var i = 0; i < element.childNodes.length; i++){

TraverseChildren(element.childNodes[i], func, depth + 1);

}

func(element, depth);

}

function ExpImgClicked(img){

var container = img.parentNode.nextSibling;

if(!container) return;

var disp = "none";

var src = window.ImgCollapsed;

if(container.style.display == "none"){

disp = "inline";

src = window.ImgExpanded;

}

container.style.display = disp;

img.src = src;

}

function SetTab(){

window.TAB = MultiplyString(2, window.SINGLE_TAB);

}

function EnsureIsPopulated(){

if(!$id("Canvas").innerHTML && !!$id("RawJson").value) Process();

}

function MultiplyString(num, str){

var sb =[];

for(var i = 0; i < num; i++){

sb.push(str);

}

return sb.join("");

}

function LinkToJson(){

var val = $id("RawJson").value;

val = escape(val.split(‘/n’).join(‘ ‘).split(‘/r’).join(‘ ‘));

$id("InvisibleLinkUrl").value = val;

$id("InvisibleLink").submit();

}

</script>

<style>

div.ControlsRow, div.HeadersRow {

font-family: Georgia;

}

div.Canvas

{

font-family: Lucida Console, Georgia;

font-size: 13px;

background-color:#ECECEC;

color:#000000;

border:solid 1px #CECECE;

}

.ObjectBrace

{

color:#00AA00;

font-weight:bold;

}

.ArrayBrace

{

color:#0033FF;

font-weight:bold;

}

.PropertyName

{

color:#CC0000;

font-weight:bold;

}

.String

{

color:#007777;

}

.Number

{

color:#AA00AA;

}

.Boolean

{

color:#0000FF;

}

.Function

{

color:#AA6633;

text-decoration:italic;

}

.Null

{

color:#0000FF;

}

.Comma

{

color:#000000;

font-weight:bold;

}

PRE.CodeContainer{

margin-top:0px;

margin-bottom:0px;

}

PRE.CodeContainer img{

cursor:pointer;

border:none;

margin-bottom:-1px;

}

#CollapsibleViewDetail a{

padding-left:10px;

}

#ControlsRow{

white-space:nowrap;

font: 11px Georgia;

}

#HeaderTitle{

text-align:right;

font-size:11px;

}

#HeaderSubTitle{

margin-bottom:2px;

margin-top:0px

}

#RawJson{

width:99%;

height:130px;

}

A.OtherToolsLink { color:#555;text-decoration:none; }

A.OtherToolsLink:hover { text-decoration:underline; }

</style>

</head>

<body>

<div class="HeadersRow">

<textarea id="RawJson">

</textarea>

</div>

<div id="ControlsRow">

<input type="Button" value="Format" onClick="Process()"/>

&nbsp;

</div>

<div id="Canvas" class="Canvas"></div>

</body>

</html>