Strukturierte Mehrfachvererbung in JAVA II – Methoden durch Interfaces ersetzen

Hallo,

eine weitere Methode, JAVA-Klassen flexibler zu machen, ist die Nutzung von Interfaces zur dynamischen Erweiterung von Klassen.

Am Beispiel eines Code Generators soll die Funktionsweise verdeutlicht werden.

Im einfachsten Fall würde ein HTML-Generator folgendermaßen aussehen:

package generatorsample;

import org.w3c.dom.Node;

public class GeneratorSimple {
    
    /**
     * generates the code based on the model
     * @param root
     * @return
     * @throws Exception 
     */
    public String generateHtml(Node root) throws Exception{
        return "code generated based on DOM...";
    }
    
    public static void main(String[] args) throws Exception{
        GeneratorSimple gen = new GeneratorSimple();
        
        //test
        Node node = HTMLParser.parse("");//this is the fabolous HTMLParser class which is not part of this post
        String htmlCode = gen.generateHtml(node);
        System.err.println("html code: "+htmlCode);
    }
}

 

Wenn nun aber statt HTML lieber CSS generiert werden sollte, dann könnte man entweder einen zweiten Generator schreiben, der speziell mit CSS models umgehen kann. Oder aber man erweitert den Generator folgendermaßen:
 

package generatorsample;

import java.util.ArrayList;
import java.util.HashMap;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.UserDataHandler;
import org.w3c.dom.css.CSSStyleSheet;



public class Generator {

    /**
     * defines a specific generator (CSS/HTML/JS/...)
     */
    public static interface CodeGenerator {
        public String generate(Model model);
        public boolean supportsMime(String mime);
    }
    
    /**
     * every model providing data for the generator needs to implement this interface
     * @param  type of the model root node (here it is assumed, that the model is a tree (e.g. AST)
     */
    public interface Model{
        public String getMime();
        public T getRoot();
        public void setRoot(T root);
    } 
    
    /**
     * all registered generators
     */
    public ArrayList generators;
    
    /**
     * generates the code based on the model
     * @param model
     * @return
     * @throws Exception 
     */
    public String generate(Model model) throws Exception{
        for(CodeGenerator gen : this.generators){
            if( ! gen.supportsMime(model.getMime())){
                continue;
            }
            return gen.generate(model); 
        }
        throw new Exception("no suitable generator found for mime type '"+model.getMime()+"'");
    }
    
    public void registerGenerator(CodeGenerator gen){
        this.generators.add(gen);
    }
    
    public static void main(String[] args) throws Exception{
        Generator gen = new Generator();
        gen.registerGenerator(new CodeGenerator() {

            @Override
            public String generate(Model model) {
                return "@media screen{\n...\n}";
            }

            @Override
            public boolean supportsMime(String mime) {
                return "text/css".equals(mime);
            }
        });
        
        gen.registerGenerator(new CodeGenerator() {

            @Override
            public String generate(Model model) {
                return "";
            }

            @Override
            public boolean supportsMime(String mime) {
                return "text/html".equals(mime);
            }
        });
        
        Model htmlModel = new Model() {
            private Node root;

            @Override
            public String getMime() {
                return "text/html";
            }

            @Override
            public Node getRoot() {
                return root;
            }

            @Override
            public void setRoot(Node root) {
                this.root = root;
            }
        };
        
        Model cssModel = new Model() {
            private CSSStyleSheet root;
            
            @Override
            public String getMime() {
                return "text/css";
            }

            @Override
            public CSSStyleSheet getRoot() {
                return root;
            }

            @Override
            public void setRoot(CSSStyleSheet root) {
                this.root = root;
            }
        };
        
        //the test
        String cssCode = gen.generate(cssModel);
        System.err.println("css code: "+cssCode);
        
        
        String htmlCode = gen.generate(htmlModel);
        System.err.println("html code: "+htmlCode);
    }
}

Damit ist die „geenerate“ methode nicht mehr fix. sie kann sogar während der laufzeit ausgetauscht werden.
Die register-Methode kann wegfallen, wenn man eine Dependency Injection Technologie verwendet, wie sie z.B. in der NetBeans Platform genutzt wird (Lookup).

Schreibe einen Kommentar