Как определить тип дочернего класса из метода родительского класса без экземпляра в Java - PullRequest
0 голосов
/ 07 октября 2018

Следующий код выполняется, но моя реализация нарушает принципы SOLID.Я надеюсь, что кто-то может помочь мне изменить мой код так, чтобы он соответствовал принципам SOLID, в частности, избегая использования instanceof.

У меня есть родительский класс Parent с тремя дочерними классами: Element, Container и Wrapper.

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());

    }
}
...