首页 > 解决方案 > 如何在 Java 中从没有 Instanceof 的父类的方法中确定子类的类型

问题描述

以下代码运行,但我的实现违反了 SOLID 原则。我希望有人可以帮助我重新设计我的代码,使其遵循 SOLID 原则,特别是避免使用instanceof.

我有一个父类 ,Parent有三个子类:ElementContainerWrapper

Element简单地保存一个整数,就像一个数学标量。

Container有一个父数组 ,Parent[] contents它可以是任何子类,如数学向量。它可以是标量向量(元素)、向量向量(容器)或函数向量(包装器)。

Wrapper有一个接口,Function允许程序员为每个包装器定义一个唯一的方法。例如,一个包装器可以包含一个使元素平方的函数,而另一个包装器可以包含一个在两个容器之间获取点积的函数。

Wrapper用两个泛型类型参数化,Wrapper<Domain extends Parent,Range extends Parent>表示输入类型 Domain 和输出类型 Range。

当我尝试访问类中的Parent[] contents数组时出现了我的问题Container。由于内容可以是任何子类,并且由于每个子类对它们的add方法都有不同的定义,我发现自己不得不使用 instanceof,这违反了 SOLID 原则。

如何更改代码的结构?

public class Parent {
    public Parent add(Parent p){return null;}
}

public class Element extends Parent{
    protected int value;
    public void set(int x){ value=x; }
    public int get(){ return value; }
    public Element(){ set(0); }
    public Element(int x){ set(x); }

    @Override
    public Parent add(Parent p){
        if (p instanceof Element){
            Element e = (Element) p;
            return add(e);
        }
        else if (p instanceof Container){
            Container c = (Container) p;
            return add(c);
        }
        else return null;
    }
    public Element add(Element e){ return new Element( get()+e.get()); }
    public Container add(Container c){ return c.add(this); }
}

///I would prefer for this class to be parameterized Container<Type>, but I run into the problem of instantiating generic arrays
public class Container extends Parent{
    protected Parent[] contents;
    public int length(){ return contents.length; }
    public Container(int x){ contents = new Parent[x]; }
    public void set(int k, Parent p){ contents[k]=p; }
    public Parent get(int k){ return contents[k]; }

    ///Have to use instanceof to determine which type of output it will be
    public Parent sum(){
        Parent p;
        if(get(0) instanceof Element)
            p = new Element();
        else if (get(0) instanceof Wrapper)
            p = new Wrapper();
        else p = new Parent();
        for(int k=0;k<contents.length;++k)
            p = p.add(contents[k]);
        return p;
    }

    ///Have to use instanceof to distinguish which add to use
    @Override 
    public Parent add(Parent p){
        if (p instanceof Element){
            Element e = (Element) p;
            return add(e);
        }
        else if (p instanceof Container){
            Container c = (Container) p;
            return add(c);
        }
        else return null;
    }
    ///adds element to the first entry in the container
    public Container add(Element e){
        Container out = new Container(contents.length);
        for(int k=0;k<contents.length;++k)
            out.set(k, contents[k]);
        out.set(0, out.get(0).add(e));
        return out;
    }
    ///adds component by component
    public Container add(Container c){
        int minLength;
        if(c.length() < contents.length)
            minLength = c.length();
        else minLength = contents.length;
        Container out = new Container(minLength);
        for(int k=0;k<minLength;++k)
            out.set(k, contents[k].add( c.get(k) ));
        return out;
    }
}

public interface Function <Domain extends Parent, Range extends Parent> {
    public Range of(Domain point);
}

public class ZeroFunction<Domain extends Parent,Range extends Parent> implements Function<Domain,Range>{
    @Override
    public Range of(Domain point) {
        return (Range) new Element();
    }
}

public class Wrapper<Domain extends Parent, Range extends Parent> extends Parent{

    protected Function<Domain,Range> function;
    public Wrapper(){ function = new ZeroFunction<Domain,Range>(); }
    public Wrapper(Function<Domain,Range> x) { function = x; }
    public Range of(Domain t){ return function.of(t); }

    @Override
    public Parent add(Parent p){
        if (p instanceof Wrapper)
            return add( (Wrapper) p);
        else return null;
    }
    public Wrapper<Domain,Range> add(final Wrapper<Domain,Range> w){
        return new Wrapper<Domain,Range>( new Function<Domain,Range>(){
            public Range of(Domain point){
                try{
                    Range term = function.of(point);
                    Range summand = w.of(point);
                    Range sum = (Range) term.add(summand);
                    return sum;
                } catch(Exception e){
                    e.printStackTrace();
                    return null;
                }
            }
        });
    }
}

public class Main {
    public static void main(String[] args){
        Wrapper<Container, Element> wrapper1 = new Wrapper<Container, Element>(new Function<Container, Element>() {
            @Override
            public Element of(Container c) {
                return (Element) c.sum();
            }
        });
        Wrapper<Container, Element> wrapper2 = new Wrapper<Container, Element>(new Function<Container, Element>() {
            @Override
            public Element of(Container c) {
                return (Element) c.sum();
            }
        });
        Container wContainer = new Container(2);
        wContainer.set(0, wrapper1);
        wContainer.set(1, wrapper2);

        Wrapper<Container,Element> wrapper3 = (Wrapper<Container,Element>) wContainer.sum();

        Container eContainer = new Container(2);
        eContainer.set(0, new Element(1));
        eContainer.set(1, new Element(2));

        Element solution = wrapper3.of(eContainer);

        System.out.println(solution.get());

    }
}

标签: javagenericsinheritanceinstanceof

解决方案


推荐阅读