2016-02-08 8 views
0

Я пытаюсь использовать композитный шаблон на Java, чтобы сделать отчет, и я явно забываю, как работает перегрузка иерархии и метода.Проблема с иерархией на Composite с Java

Скажем, у меня есть следующие модели:

public class Product { 

    public String get(){ 
     return "Product"; 
    } 

} 

public class BProduct extends Product { 

    public String getB() { 
     return "BBBBB"; 
    } 

} 

public class CProduct extends Product { 

    public String getC() { 
     return "CCCCC"; 
    } 

} 

И следующие преобразователи:

import java.util.List; 

public class Converter { 

    private List<Converter> converters; 

    public Converter() { 

    } 

    public Converter(List<Converter> converters) { 
     this.converters = converters; 
    } 

    public void execute(Product product) { 
     for (Converter converter : converters) { 
      converter.execute(product); 
     } 
    } 

} 

public class BConverter extends Converter { 

    @Override 
    public void execute(Product product) { 
     innerExecute(product); 
    } 

    public void innerExecute(Product product) { 
     System.out.println(product.get() + " done on B normal."); 
    } 

    public void innerExecute(BProduct b) { 
     System.out.println(b.getB() + " done on B special."); 
    } 

} 

public class CConverter extends Converter { 

    @Override 
    public void execute(Product product) { 
     System.out.println(product.get() + " done on C normal."); 
    } 

    public void execute(CProduct c) { 
     System.out.println(c.getC() + " done on C special."); 
    } 

} 

Тестирование с помощью следующей тест:

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

import org.junit.Test; 

public class ProductConverterTest { 

    @Test 
    public void test() { 
     List<Converter> converters = new ArrayList<>(); 
     converters.add(new BConverter()); 
     converters.add(new CConverter()); 
     Converter converter = new Converter(converters); 

     List<Product> list = new ArrayList<>(); 
     list.add(new Product()); 
     list.add(new BProduct()); 
     list.add(new CProduct()); 

     for (Product product : list) { 
      converter.execute(product); 
     } 
    } 
} 

Gets в качестве вывода:

Product done on B normal. 
Product done on C normal. 
Product done on B normal. 
Product done on C normal. 
Product done on B normal. 
Product done on C normal. 

Когда я хочу это:

Product done on B normal. 
Product done on C normal. 
BBBBB done on B special. 
Product done on C normal. 
Product done on B normal. 
CCCCC done on C special. 

ПРИМЕЧАНИЕ: Я хочу сделать это без использования instanceof. Я уже знаю, как это сделать с этим. Я хочу знать, можно ли это сделать без него.

ответ

1

Причина такого поведения в том, что метод #execute перегружен. выбор которого перегружает метод для вызова, выполняется во время компиляции. для того, чтобы заставить его работать, как вы хотите, вы должны использовать динамический выбор, который приведет либо instanceOf чека или перезапись методы или передать/получить класс в product и сравнить, как:

public class Converter { 

    private List<Converter> converters; 

    public Converter() { 

    } 

    public Converter(List<Converter> converters) { 
     this.converters = converters; 
    } 

    public void execute(Product product) { 
     for (Converter converter : converters) { 
      converter.execute(product); 
     } 
    } 

} 

public class BConverter extends Converter { 

    @Override 
    public void execute(Product product) { 
     if (product.getClass() == BProduct.class) { 
      innerExecute((BProduct)product); 
     } else { 
      innerExecute(product); 
     } 
    } 

    public void innerExecute(Product product) { 
     System.out.println(product.get() + " done on B normal."); 
    } 

    public void innerExecute(BProduct b) { 
     System.out.println(b.getB() + " done on B special."); 
    } 

} 

public class CConverter extends Converter { 

    @Override 
    public void execute(Product product) { 
     if (product.getClass() == CProduct.class) { 
      innerExecute((CProduct)product); 
     } else { 
      innerExecute(product); 
     } 
    } 

    public void innerExecute(Product product) { 
     System.out.println(product.get() + " done on C normal."); 
    } 

    public void innerExecute(CProduct b) { 
     System.out.println(b.getC() + " done on C special."); 
    } 

} 
0

Ваш метод выполнения в субконвертерах всегда вызывает метод innerExecute из высшего класса. В вашем примере удалите innerExecute (Профайл продукта) из подклассов.

Вы также можете попытаться перезаписать toString() - Methode в продукте вместо get-method. Затем используйте интерфейс для метода execute.