Composite template and instance

Imagine the following situation: I want to create a bidding application (e.g. ebay) with a composite design pattern

I am creating an abstract superclass, such as "BidComponent" (which has getName ()) and two subclasses of "Article" and "Category".

There is a list in the category that may contain other BidComponents, the article does not implement List, but the getPrice () method.

If I want to iterate over this structure and want to print the structure-article, I need an instance:

if(element instanceof Article){
  Article article = (Article)element;
  System.out.println(article.getName() + ":" + article.getPrice());
}else{
  Category category = (Category)element;
  System.out.println(category.getName());
}

This seems to me wrong. Is there a better way to implement this (So without checking the type through instanceof)? I ask this question because I read several times that using instanceof is a bad design ...

// Edit to mention my problem with visitors:

Ok. , . ,

public class HighestBidVisitor implements BidComponentVisitor{
    private double highestBid = 0d;

    public HighestBidVisitor(Category category){
        visitCategory(category);
    }

    @Override        
    public void visitCategory(Category category){
        Iterator<BidComponent> elementsIterator = category.iterator();
        while(elementsIterator.hasNext()){
            BidComponent bidComponent = elementsIterator.next();

            //Now I have again the problem: I have to check if a component in the Categorylist is an article or a category
            if(bidComponent instanceof Article) visitArticle((Article)bidComponent);
            else visitCategory((Category)bidComponent);

        }
    }

    @Override
    public void visitArticle(Article article){
        if(article.getPrice() > highestBid) highestBid = article.getPrice();
    }


}

(. visitCategory). ?

+4
3

.

public interface BidComponentVisitor {

  void visitArticle(Article article);

  void visitCategory(Category category);
}

BidComponent :

public abstract void visitChildren(BidComponentVisitor visitor);

.

: instanceof vistor , visitChildren. Category :

@Override
public void visitChildren(BidComponentVisitor visitor) {
  vistor.visitCategory(this);
  for (BidComponent child : children) {
    child.visitChidren(visitor);
  }
}

Article , :

@Override
public void visitChildren(BidComponentVisitor visitor) {
  vistor.visitArticle(this);
}

- , , .

:

public interface BidComponentVisitor {

  void visitArticle(Article article);

  void enterCategory(Category category);

  void exitCategory(Category category);
}

Category.visitChildren() :

@Override
public void visitChildren(BidComponentVisitor visitor) {
  vistor.enterCategory(this);
  for (BidComponent child : children) {
    child.visitChidren(visitor);
  }
  vistor.exitCategory(this);
}

, - :

public class PrintingVisitor implements BidComponentVisitor {
  private int depth = 0;

  private void printIndent() {
    for (int i = 0; i < depth; i++) {
      System.out.print("  ");
    }
  }

  public void visitArticle(Article article) {
    printIndent();
    System.out.println(article.toString());
  }

  public void enterCategory(Category category);
    printIndent();
    System.out.println(category.toString());
    depth++;
  }

  public void exitCategory(Category category) {
    depth--;
  }
}

, , visitOther().

+2

. . , , - .

public interface Visitor{
   void visit(Article a);

   void visit(Category c);

}

abstract class BidComponent{
   ...
   abstract void accept(Visitor v);
}

public class Category{

  ....
  public void accept(Visitor v){
      v.visit(this); // visit Category
      for(Article a : getArticles()){
         v.visit(a); //visit each article
      }
  }
}

public class HigestBidVisitor implements Visitor{
   private final double highest;

   void visit(Category c){
      //no-op don't care

      //or we could track which Category we have visited last
      //to keep track of highest bid per category etc
   }

   void visit(Article a){
      highest= Math.max(highest, a.getPrice());          
   }
}

:

HigestBidVisitor visitor = new HighestBidVisitor();

BidComponent root = ...

root.accept(visitor); 
double highest = visitor.getHighestPrice();
+2

. , , Article Category .

, List<BidComponent>, , :

abstract class BidComponent {
    public abstract String process();
}

class Category extends BidComponent {
    @Override
    public String process() {
        return getName();
    }
} 

class Article extends BidComponent {
    @Override
    public String process() {
        return getName() + " " + getPrice();
    }
}


List<BidComponent> list = ..;
for (BidComponent c : list) {   
    System.out.println(c.process());
}

/:

Map<Class<?>, Function<BidComponent, String>> processors = new HashMap<>();
processors.put(Category.class, Category::getName());
processors.put(Article.class, a -> a.getName() + " " + a.getPrice());

List<BidComponent> list = ..;
for (BidComponent c : list) {
    System.out.println(processors.get(c.getClass()).apply(c));
}

, Java 8 lambdas, Java 7 , ( Function) , Guava Apache Commons.

+1

Source: https://habr.com/ru/post/1570712/


All Articles