简体   繁体   中英

Decorator Design Pattern in Java - why it doesnt add new ingridients to list?

I tried to implement a simple Decorator Pattern in Java. The main idea is that a concrete decorator have to add something to the basic list. However, my implementation doesnt work correctly and I dont know why.

The output is as you see below:

ING -1,ING 0,ING 1.

but it should be:

ING -1,ING 0,ING 1, ING 2.

Heres my code:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package newpackage;

import java.util.ArrayList;
import java.util.List;

abstract class Tester {

    protected List<String> ingridients = new ArrayList();
    protected String description;

    public String getDescription() {
        description = "";
        for (String i : ingridients) {
            description += i;
            description += ",";
        }
        description = description.substring(0, description.length() - 1);
        description += ".";
        return description;
    }
}

abstract class Decorator extends Tester {

    @Override
    public abstract String getDescription();
}

class Test1 extends Tester {

    public Test1() {
        this.ingridients.add("ING -1");
        this.ingridients.add("ING 0");
    }
}

class Ing1 extends Decorator {

    private Tester t;

    public Ing1(Tester t) {
        this.t = t;
    }

    @Override
    public String getDescription() {
        this.t.ingridients.add("ING 1");
        return this.t.getDescription();
    }
}

class Ing2 extends Decorator {

    private Tester t;

    public Ing2(Tester t) {
        this.t = t;
    }

    @Override
    public String getDescription() {
        this.t.ingridients.add("ING 2");
        return this.t.getDescription();
    }
}

public class Test {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Tester t = new Test1();
        t = new Ing1(t);
        t = new Ing2(t);

        System.out.println(t.getDescription());
    }
}

Edited code:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package newpackage;

import java.util.ArrayList;
import java.util.List;

interface Tester {

    List<String> ingridients = new ArrayList();
    public String getDescription();
}

abstract class Decorator implements Tester {

    @Override
    public abstract String getDescription();
}


class Test1 implements Tester {

    public Test1() {
        ingridients.add("ING -1");
        ingridients.add("ING 0");
    }

    @Override
    public String getDescription() {
        String description = "";
        for (String i : ingridients) {
            description += i;
            description += ",";
        }
        description = description.substring(0, description.length() - 1);
        description += ".";
        return description;
    }
}

class Ing1 extends Decorator {

    private Tester t;

    public Ing1(Tester t) {
        this.t = t;
    }

    @Override
    public String getDescription() {
        this.t.ingridients.add("ING 1");
        return this.t.getDescription();
    }
}

class Ing2 extends Decorator {

    private Tester t;

    public Ing2(Tester t) {
        this.t = t;
    }

    @Override
    public String getDescription() {
        this.t.ingridients.add("ING 2");
        return this.t.getDescription();
    }
}

public class Test {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Tester t = new Test1();
        t = new Ing1(t);
        t = new Ing2(t);

        System.out.println(t.getDescription());
    }
}

I run this in a debugger and I could see that your Decorators are not just decorators as they have state of their own. Make your Tester an interface and have you decorators only wrap the concrete instances and not have state of their own.

// adds to the list in t1
this.t.ingridients.add("ING 2");

// add to the list in t
this.t.ingridients.add("ING 1");

// returns the contents of t.
return this.t.getDescription();

At the end t.ingredients has three items, t1.ingredients has 1 element and t2.ingredients has none.


You could write it this way

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class Test {
    public static void main(String[] ignored) {
        Tester t012 = new Ing2(new Ing1(new Ing0(new None())));
        System.out.println(t012.getDescription());

        Tester t210 = new Ing0(new Ing1(new Ing2(new None())));
        System.out.println(t210.getDescription());
    }
}

abstract class Tester {
    public List<String> getIngredients() {
        return Collections.emptyList();
    }

    public String getDescription() {
        StringBuilder sb = new StringBuilder();
        String sep = "";
        for (String s : getIngredients()) {
            sb.append(sep).append(s);
            sep=", ";
        }
        sb.append(".");
        return sb.toString();
    }
}

class None extends Tester {
}

class Ing0 extends Tester {
    private final Tester wrapped;
    Ing0(Tester wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public List<String> getIngredients() {
        List<String> list = new ArrayList<>(wrapped.getIngredients());
        list.add("ING -1");
        list.add("ING 0");
        return Collections.unmodifiableList(list);
    }
}

class Ing1 extends Tester {
    private final Tester wrapped;
    Ing1(Tester wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public List<String> getIngredients() {
        List<String> list = new ArrayList<>(wrapped.getIngredients());
        list.add("ING 1");
        return Collections.unmodifiableList(list);
    }
}

class Ing2 extends Tester {
    private final Tester wrapped;
    Ing2(Tester wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public List<String> getIngredients() {
        List<String> list = new ArrayList<>(wrapped.getIngredients());
        list.add("ING 2");
        return Collections.unmodifiableList(list);
    }
}

prints

ING -1, ING 0, ING 1, ING 2.
ING 2, ING 1, ING -1, ING 0.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM