Avoid static binding in operations which use hierarchy arguments

*爱你&永不变心* 提交于 2019-12-09 01:49:16

问题


I have found an issue about static binding.

My real class are very extended, so I will use several toy class to express my problem.

We suppose that we have the following hierarchy.

public class Element{}

public class Element1 extends Element{}

public class Element2 extends Element{}

I have a Stock class which use the different Element specialization defined by Element hierarchy.

public class Stock{

    public void operation(Element1 e1){
        System.out.println("Operation - " + e1.getClass().getName());
    }

    public void operation(Element2 e2){
        System.out.println("Operation - " + e2.getClass().getName());
    }
}

Finally, I have a StockManager which allows to manage a Stock.

public StockManager{

    Stock stock;
    public StockManager(Stock stock){
        this.stock=stock;
    }

    public void manage(List<Element> elements){
        for(Element element: elements){
            stock.operation(element);
        }
    }
}

Of course, this code does not compile, because Stock does not define a method which includes a Element as argument. In this case we could fix the code using different approaches.

First, I will be able to define a method which will define a Element as input arg, e.g.

public void operation(Element e){
    System.out.println("Operation - " + e.getClass().getName());
}

This method could define a switch for managing the different concrete elements (Element1, Element2). However, this is imposible for me, because the switch violate the Open/Close Principle, and I have a lot (a lot) of concrete elements.

Another alternative, I could use something like the Visitor Pattern. I could send the Stock object to a concrete element. And the concrete element will be charge of using the Stock operations. So, the class could change to:

public abstract class Element{
    public abstract void stockOperation(Stock stock);
}

public class Element1 extends Element{
    public abstract void stockOperation(Stock stock){
        stock.operation(this);
    }
}

public class Element2 extends Element{
    public abstract void stockOperation(Stock stock){
        stock.operation(this);
    }
}

And the StockManager.

public StockManager{

    Stock stock;
    public StockManager(Stock stock){
        this.stock=stock;
    }

    public void manage(List<Element> elements){
        for(Element element: elements){
            element.stockOperation(stock);
        }
    }
}

It allows determine in compile-time the static type of the concrete elements. And the dynamic binding will be charge of call the stockOperation method of the correct concrete element (Element1 or Element2). HOWEVER!!, I have duplicate code in the concrete elements, and I will have several concrete elements.

So, I would like know if we know any pattern design or any best practice for solve this issue. (Another alternative, it maybe to use reflection, but I would not like use it).


回答1:


The problem is that you place the individual stock operations in the stock object. No matter if you use a switch or not, as soon as you have another Element type, you'll need to modify stock by adding a new overloaded operation to it. And as you said, your Stock class should be closed to modifications.

So you have to do relegate whatever the stock operation is to the Element object itself. This is basically your second suggestion, but you do the implementation in each different Element.

public abstract class Element{
    public abstract void stockOperation(Stock stock);
}

public class Element1 extends Element{
    @Override
    public void stockOperation(Stock stock){
        System.out.println("Operation - Element1");
    }
}

public class Element2 extends Element{
    @Override
    public void stockOperation(Stock stock){
        System.out.println("Operation - Element2");
    }
}

You will probably need to communicate with the stock object for the real operations. Do that with the stock that was passed to each stockOperation, making methods available that allow the elements to get or set whatever is needed inside the stock object, like the result of the operation.

This way, if you have a new Element type, you only need to write the new operation in the new Element, and you can keep the same Stock class without changing it. This is extension rather than modification.



来源:https://stackoverflow.com/questions/26553300/avoid-static-binding-in-operations-which-use-hierarchy-arguments

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!