vendredi 25 août 2017

Impelementing real life Command design pattern

Its not a duplicate, since it is a real life project. I have several Xml files. Every entry in all of them have id and name tags. Some others have extra like type, date and so on. I have a base parser class which makes objects form xml files. The example xml files are:

food.xml and some others just have id and name:

<foods>
    <food>
        <id>1</id>
        <name>bread</name>
    </food>
</foods>

some files have extra tags:

<treatments>
        <treatment>
            <id>1</id>
            <name>pill</name>
            <type>daily</type>
        </treatment>
</treatments>

The base parser class that extracts id and name for xml files is:

public class PreDefinedEffectiveParser extends XmlHelper {
    public PreDefinedEffectiveParser(String xml_string) {
        super(xml_string);
    }

    protected <T extends PreDefinedEffectiveDataModel> List<T> parse(Class<T> cls, String tag_name) {
        List<T> result = new ArrayList<>();

        NodeList treatmentList = document.getElementsByTagName(tag_name);
        for(int i=0; i<treatmentList.getLength(); i++){
            Element element = (Element) treatmentList.item(i);

            try {
                T dataModel = cls.newInstance();
                try {
                    dataModel.setName(getValue(element, "name"));
                } catch (Exception ex) {
                }
                try {
                    dataModel.setId(Long.parseLong(getValue(element, "id")));
                } catch (Exception ex) {
                }
                result.add(dataModel);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        return result;
    }
}

and FoodParser which extends base parser is:

public class FoodParser extends PreDefinedEffectiveParser {
    public FoodParser(String xml_string) {
        super(xml_string);
    }

    public List<FoodDataModel> parse(){
        return parse(FoodDataModel.class, "food");
    }
}

For the parser classes which have extra tags, i rewrite the parse() method that takes a lot of time and is cumbersome and most of them are copy of base class's parse() method. like:

public class TreatmentParser extends PreDefinedEffectiveParser {
    public TreatmentParser(String xml_string) {
        super(xml_string);
    }

    public List<TreatmentDataModel> parse(){
        List<TreatmentDataModel> result = new ArrayList<>();

        try {
            NodeList treatmentList = this.document.getElementsByTagName("treatment");

            for (int i = 0; i < treatmentList.getLength(); i++) {
                Element treatElem = (Element) treatmentList.item(i);
                TreatmentDataModel dataModel = new TreatmentDataModel();

                try {
                    dataModel.setId(Long.parseLong(getValue(element, "id")));
                } catch (Exception ex) {
                }

                try {
                    dataModel.setName(getValue(treatElem, "name"));
                } catch (Exception ex) {}

                try {
                    TreatmentType type = TreatmentType.factory(getValue(treatElem, "type"));
                    dataModel.setTreatmentType(type);
                } catch (Exception ex) {}

                result.add(dataModel);
            }
        }
        catch (Exception ex) {}

        return result;
    }
}

Since I have lots of different xml files with variable number of tags, how can i use command pattern to faciliate setting Data model objects easily like this:

public class TreatmentParser extends PreDefinedEffectiveParser {
    List<String> tags = new ArrayList<>();
    List<FunctionPtr> methods = new ArrayList<>();

    public TreatmentParser(String xml_string) {
        super(xml_string);

        // The trick is hear
        tags.add("id");
        methods.add(TreatmentDataModel.setId);  // <== Excuse me!

        tags.add("name");
        methods.add(TreatmentDataModel.setName);

        tags.add("type");
        methods.add(TreatmentDataModel.setType);
    }

    public List<TreatmentDataModel> parse(){

    for ( int i=0; i < tags.size(); i++ ) {
        invoke_function( methods.get(i) ) with parameter getValue(tags.get(i));
    }

    return some result;
}

Note: I don't want to use lambda or reflection. I want to implement by Command pattern to deeply understand it. Thanks in advanced.

Aucun commentaire:

Enregistrer un commentaire