Dagi3d v4

Patrón Plug-In

(Aviso, este post me ha salido un poco largo y no hay dibujitos face-smile.png )

Hoy con todos ustedes, el patrón plug-in.

La utilización de este patrón permite crear objetos en tiempo de ejecución, teniendo como requisito que la clase que acabamos de instanciar, implemente una determinada interfaz para poder tratar las distintas clases plugin por igual.

¿Y esto para que sirve? Con esto conseguiremos enchufar nuevas clases a la aplicación sin necesidad de modificar el código fuente original ni compilar el programa de nuevo, lo que nos permitiría una mayor modularidad en el programa además de ofrecer la posibilidad de que un tercero añada nuevas funcionalidades al programa de manera más fácil.

Por ejemplo, supongamos que estamos desarrollando un procesador de texto y queremos crear varios filtros para los textos pero ofreciendo la posibilidad de ir añadiendo nuevos o quitarlos sin tocar la aplicación.

Primero creamos la interfaz Plugin:

Plugin.java

package net.dagi3d;

/**
 * @author Borja Martín
 */
public interface Plugin
{
    public String getName();

    public String process(String text);
}

La interfaz se puede complicar tanto como el desarrollador de la api quiera o necesite. En este caso basta con que implementen el método process(String) para manipular el texto y getName() para indicarle al programa un nombre amigable del plugin, que será el que se muestre al usuario de la aplicación.

Ahora bastará que los plugins que queramos crear implementen esta interfaz. He escrito dos ejemplos muy simples, uno que invierte las mayúsculas y mínusculas del texto y otro que pone en mayúsculas la primera letra de cada palabra:

SwapCasePlugin.java

package net.dagi3d;

/**
 * @author Borja Martín
 */
public class SwapCasePlugin implements Plugin
{

    public String getName()
    {
        return "SwapCase";
    }

    public String process(String text)
    {
        char[] chars = text.toCharArray();

        for (int i = 0; i < chars.length; i++)
        {
            char c = chars[i];

            c = (c == Character.toUpperCase(c)) 
                ? Character.toLowerCase(c)
                : Character.toUpperCase(c);

            chars[i] = c;
        }

        return new String(chars);
    }
}

CapitalizePlugin.java

package net.dagi3d.plugin;

import java.util.StringTokenizer;

/**
 * @author Borja Martín
 */
public class CapitalizePlugin implements Plugin
{
    public String getName()
    {
        return "Capitalize";    
    }

    public String process(String text)
    {
        StringBuffer sb = new StringBuffer();
        StringTokenizer st = new StringTokenizer(text);

        while (st.hasMoreTokens())
        {
            String word = st.nextToken();
            word = Character.toUpperCase(word.charAt(0)) + word.substring(1);
            sb.append(word);
            sb.append(" ");
        }

        String modifiedText = sb.toString().trim();

        return modifiedText;
    }
}

Y ahora un pequeño programa de prueba en el que cargaremos los plugins que indiquemos en un fichero de texto. Otra opción (más cómoda de cara al usuario) sería leer directamente de una carpeta donde se copiarían los .class o los plugins empaquetados en un jar y así no sería necesario tocar ningún fichero de configuración, pero elegí la primera opción para simplificar el ejemplo :

plugin.properties

net.dagi3d.plugin.CapitalizePlugin
net.dagi3d.plugin.SwapCasePlugin

PluginTest.java

package net.dagi3d;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import net.dagi3d.plugin.Plugin;

/**
 * @author Borja Martín
 */
public class PluginTest
{
    private static List _plugins = new ArrayList();

    private static final String TEXT = 
            "lorem ipsum dolor sit amet consectetuer adipiscing elit.";

    private static final String PLUGINS_FILE = "./plugin.properties";

    public static void main(String[] args)
    {
        loadPlugins();

        System.out.println("Texto original => " + TEXT);

        for (int i = 0; i < _plugins.size(); i++)
        {
            Plugin plugin = (Plugin) _plugins.get(i);
            System.out.println(plugin.getName() + " => " + plugin.process(TEXT));
        }
    }

    private static void loadPlugins()
    {
        String className = null;

        try 
        {
            _plugins.clear();

            File f = new File(".");

            BufferedReader in = new BufferedReader(new InputStreamReader(
                    new FileInputStream(PLUGINS_FILE)));

            while ((className = in.readLine()) != null)
            {
                Class pluginClass = Class.forName(className);
                Plugin plugin = (Plugin) pluginClass.newInstance();
                _plugins.add(plugin);
            }
        }
        catch (ClassNotFoundException e)
        {
            System.err.println("Plugin no encontrado: " + className);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

Si ejecutamos el programa obtendríamos la siguiente salida:
Texto original => lorem ipsum dolor sit amet consectetuer adipiscing elit.
Capitalize => Lorem Ipsum Dolor Sit Amet Consectetuer Adipiscing Elit.
SwapCase => LOREM IPSUM DOLOR SIT AMET CONSECTETUER ADIPISCING ELIT.

Y cuando quisieramos añadir un nuevo plugin a la aplicación, sería suficiente con añadirlo al fichero ‘plugin.properties’ y que el .class esté en el CLASSPATH

Luego todo esto ya se puede complicar lo que uno quiera, añadiendo por ejemplo parámetros a los distintos plugins.

Aquí está el código fuente del ejemplo(está como proyecto de Eclipse): patron_plugin.zip

lasterra
05/02/2006 08:22

Uno de mis preferidos. Lo use para las Rules de lo Formularios de Cáñamo. En ellas cada regla hace una validación diferente, Que los parametros del formulario no sean nulos, que uno sea igual q otro, etc, etc. A traves del patrón permito crear al programador reglas de validación para su aplicación.

Gustavo Antonio López Cambambia
10/11/2006 07:51

podrias generar un codigo para hacer un analizador lexico y sintactico de un texto introducido en un textarea y mandarmelo?

Deja un comentario
*: campos obligatorios. La dirección de correo no será publicada