Let's say I have a base class:
Class A {
public String field1;
public A(String field1){
this.field1 = field1;
}
}
And a devired class:
Class B extends A {
public String field2;
}
Let's say I have a List<A> listA
, how can I create a constructor so I can easily turn this list to List<B> listB
? I want to have a constructor in B class
that will take A object
and fill in all the fields from A
in B
and have some logic to construct new fields. Something like this:
Class B extends A {
public String field2;
public B (A a){
this = a;
this.field2 = doLogic(a);
}
}
Or at least just fill in all the fields from A in B:
public B(A a){
this = a;
}
So later I can just manually set the field from B
, to something like this:
listA.stream().map(x -> new B(x)).map(x -> x.setField2(logic(x)));
I know I can do it like this:
Class B extends A {
public String field2;
public B(A a){
super(a.getField1());
}
}
But this just doesn't look right to me, getting the fields of the object just to call a constructor of the same class.
What if the base class has a lot of fields, will you need to get all of the fields to call in the constructor? It doesn't look good, so I'm wondering if is there any better way.
CodePudding user response:
What if the base class has a lot of fields
The first question of course would be why you need that and whether there might be another way. In this answer I'll assume you've already answered that question and came to the conclusion you need it.
Let's say I have a
List<A> listA
, how can I create a constructor so I can easily turn this list toList<B> listB
?
You could do a copy constructor and maybe also do something like this:
class A {
A(A other) {
//copy fields
}
}
class B extends A {
B(A other) {
super(other);
//init B fields
}
}
With this in place you can use plain iteration or streaming to turn a List<A>
into a List<B>
:
List<B> convertedList = origList.stream().map(a -> new B(a)).collect(Collectors.toList());
Another option might be delegation but that would depend on your classes:
class B extends A {
A delegate;
B(A delegate) {
this.delegate = delegate;
//init B fields
}
@Override
void setField1(String value) {
delegate.setField1(value);
}
@Override
String getField1() {
return delegate.getField1();
}
}
Doing it like this would leave B's "field1" empty so it might not be the best option. If you have an interface for A it would look similar but leave less "empty" fields:
interface AInterface {
void setField1(String value);
String getField1();
}
class A implements AInterface {
...
}
class B implements AInterface {
AInterface delegate;
B(AInterface delegate) {
this.delegate = delegate;
//init B fields
}
@Override //this is not an actual override but an implementation
public void setField1(String value) {
delegate.setField1(value);
}
@Override //this is not an actual override but an implementation
public String getField1() {
return delegate.getField1();
}
}