Следующий код выполняется, но моя реализация нарушает принципы 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());
}
}