Recursive Generic and Fluent Interface - java

tl;dr
Trying to implement a hierarchal fluent interface such that I can combine nodes child classes while also the class standalone, but getting type parameter is not within its bound errors.
Details
I'm trying to achieve a solution so that I can create something such that I can do something like:
farm
.animal()
.cat()
.meow()
.findsHuman()
.saysHello()
.done()
.done()
.dog()
.bark()
.chacesCar()
.findsHuman()
.saysHello()
.done()
.done()
.done()
.human()
.saysHello()
.done();
while also being able to do:
Human human = new Human()
.saysHello()
I've gotten close using various strategies but haven't been able to gain the flexibility described.
My current attempt uses the following classes:
abstract class Base<T extends Base<T>>{
private T parent;
Base(){
}
Base( T parent ){
this.parent = parent;
}
public T done() throws NullPointerException{
if ( parent != null ){
return (T) parent;
}
throw new NullPointerException();
}
}
class Farm<T extends Base<T>> extends Base{
private Animal<Farm<T>> animal;
private Human<Farm<T>> human;
public Farm(){
super();
this.animal = new Animal( this );
this.human = new Human( this );
}
public Animal<Farm> animal(){
return this.animal;
}
public Human<Farm<T>> human(){
return this.human;
}
}
class Animal <T extends Base<T>> extends Base{
private Cat<Animal<T>> cat;
private Dog<Animal<T>> dog;
public Animal(){
super();
init();
}
public Animal( T parent ){
super( parent );
init();
}
private void init(){
this.cat = new Cat(this);
this.dog = new Dog(this);
}
public Cat<Animal<T>> cat(){
return cat;
}
public Dog<Animal<T>> dog(){
return dog;
}
}
class Human<T extends Base<T>> extends Base{
public Human<T> saysHello(){
System.out.println("human says hi");
return this;
}
}
class Cat <T extends Base<T>> extends Base{
private Human<Cat> human;
public Cat(){
super();
init();
}
public Cat( T parent ){
super( parent );
init();
}
private void init(){
this.human = new Human();
}
public Cat<T> meow(){
System.out.println("cat says meow");
return this;
}
public Human<Cat<T>> findsHuman(){
return this.human;
}
}
class Dog <T extends Base<T>> extends Base{
private Human<Dog> human;
public Dog(){
super();
init();
}
public Dog( T parent ){
super( parent );
init();
}
private void init(){
this.human = new Human();
}
public Dog<T> bark(){
System.out.println("dog says woof");
return this;
}
public Dog<T> chacesCar(){
System.out.println("cat drinks milk");
return this;
}
public Human<Dog<T>> findsHuman(){
return this.human;
}
}
The errors I'm seeing are commonly:
Animal.java:4: type parameter Animal is not within its bound private Cat cat;
Animal.java:5: type parameter Animal is not within its bound private Dog dog;
Applied to all similar references and also pertaining to my example desired case:
cannot find symbol
symbol : method dog()
location: class Base.dog()
I've tried using the following solutions which seemed to tackle similar problems, but to no avail, so any and all support is welcome.
References
Is there a way to refer to the current type with a type variable?
http://vyazelenko.com/2012/03/02/recursive-generics-to-the-rescue/

The code below seems to work fine and doesn't need any #SuppressWarnings. The key concept to grasp is that your T parameter is effectively the class of your object's parent, but T's parent could be anything. So instead of T extends Base<T> you want T extends Base<?>.
The output is:
cat says meow
human says hi
dog says woof
cat drinks milk
human says hi
human says hi
...which I believe is correct, although you might want to change your Dog.chacesCar() method so it doesn't output cat drinks milk! Also it should be chases not chaces.
Hope this helps!
abstract class Base<T extends Base<?>> {
private final T parent;
Base() {
this.parent = null;
}
Base(T parent) {
this.parent = parent;
}
public T done() throws NullPointerException {
if (parent != null) {
return parent;
}
throw new NullPointerException();
}
}
class Farm<T extends Base<?>> extends Base<T> {
private final Animal<Farm<T>> animal;
private final Human<Farm<T>> human;
public Farm() {
super();
this.animal = new Animal<>(this);
this.human = new Human<>(this);
}
public Animal<Farm<T>> animal() {
return this.animal;
}
public Human<Farm<T>> human() {
return this.human;
}
}
class Animal<T extends Base<?>> extends Base<T> {
private Cat<Animal<T>> cat;
private Dog<Animal<T>> dog;
public Animal() {
super();
init();
}
public Animal(T parent) {
super(parent);
init();
}
private void init() {
this.cat = new Cat<>(this);
this.dog = new Dog<>(this);
}
public Cat<Animal<T>> cat() {
return cat;
}
public Dog<Animal<T>> dog() {
return dog;
}
}
class Human<T extends Base<?>> extends Base<T> {
public Human() {
super();
}
public Human(T parent) {
super(parent);
}
public Human<T> saysHello() {
System.out.println("human says hi");
return this;
}
}
class Cat<T extends Base<?>> extends Base<T> {
private Human<Cat<T>> human;
public Cat() {
super();
init();
}
public Cat(T parent) {
super(parent);
init();
}
private void init() {
this.human = new Human<>(this);
}
public Cat<T> meow() {
System.out.println("cat says meow");
return this;
}
public Human<Cat<T>> findsHuman() {
return this.human;
}
}
class Dog<T extends Base<?>> extends Base<T> {
private Human<Dog<T>> human;
public Dog() {
super();
init();
}
public Dog(T parent) {
super(parent);
init();
}
private void init() {
this.human = new Human<>(this);
}
public Dog<T> bark() {
System.out.println("dog says woof");
return this;
}
public Dog<T> chacesCar() {
System.out.println("cat drinks milk");
return this;
}
public Human<Dog<T>> findsHuman() {
return this.human;
}
}
Test code:
public static void main(String[] args) {
Farm<?> farm = new Farm<>();
farm
.animal()
.cat()
.meow()
.findsHuman()
.saysHello()
.done()
.done()
.dog()
.bark()
.chacesCar()
.findsHuman()
.saysHello()
.done()
.done()
.done()
.human()
.saysHello()
.done();
Human human = new Human()
.saysHello();
}

The best thing I came up is the following:
new Animal()
.cat()
.meow()
.findsHuman()
.<Cat>done()
.<Animal>done()
.dog()
.bark()
.findHuman()
.<Dog>done()
.done();
With the following base class:
public abstract class Base<T extends Base<T>>{
private Base<?> backRef;
public Base() {}
public Base(Base<?> backRef) {
this.backRef = backRef;
}
#SuppressWarnings("unchecked")
protected T self() {
return (T)this;
}
#SuppressWarnings("unchecked")
public <U extends Base<U>> U done() {
return (U)backRef;
}
}
If you declare backRef as of Type T then the other classes are not allowed because they are not a subclasses of each other, so you have to specify a different type, but since this type is context dependent (one time its Cat, one time its Dog) I don't see an alternative as to pass a hint.
I found a solution:
new Animal()
.cat()
.meow()
.findsHuman()
.done()
.done()
.dog()
.bark()
.findHuman()
.done()
.done();
public abstract class Base<T extends Base<T,P>, P>{
private P backRef;
public Base() {}
public Base(P backRef) {
this.backRef = backRef;
}
#SuppressWarnings("unchecked")
protected T self() {
return (T)this;
}
public P done() {
return backRef;
}
}
Like someone suggested, we add an additional Type for the parent.
Now the base classes:
public final class Cat extends Base<Cat, Animal>{
public Cat() {}
public Cat(Animal backRef) {
super(backRef);
}
public Cat meow() {
System.out.println("Meeeoooww");
return self();
}
public Human<Cat> findsHuman() {
return new Human<Cat>(this);
}
}
As you can see, Cat clearly specifies which base type it should use. Now for human, which can change the type depending on the context:
public final class Human<P> extends Base<Human<P>, P> {
public Human() {}
public Human(P backRef) {
super(backRef);
}
}
Human specifies an additional generic which the caller (Cat, Dog) specifies in their findHuman() Method.

This is what we did on one our project:
public abstract class Parent<T extends Parent<T>> {
/**
* Get {#code this} casted to its subclass.
*/
#SuppressWarnings("unchecked")
protected final T self() {
return (T) this;
}
public T foo() {
// ... some logic
return self();
}
// ... other parent methods
}
public class Child extends Parent<Child> {
public Child bar() {
// ... some logic
return self();
}
// ... other child methods
}
Allowing child to have its own subclass would be:
public class Child<T extends Child<T>> extends Parent<T> {
public T bar() {
// ... some logic
return self();
}
}

In this line:
class Farm<T extends Base<T>>
The compiler treats the second type parameter as a concrete class. For example, say if you replaced that line with this:
class Farm<T extends Base<Double>>
'Double' is a concrete class. When the compiler scans this, it cannot tell the difference between your T and Double, and such treats them both as concrete class, and not type parameters. The only way to let the compiler know T is a type parameter is this way:
class Farm<T extends Base<T>, T>
I hope this answers (or is at least relevant) to your question.
edit
Post was edited while I was typing, so I guess this answer isn't relevant anymore.

You could also play with interfaces, so that you can fake multiple inheritance. A bit verbose, but there is no hazardous casting, and I find it quite understandable.
Define the available methods:
public interface AnimalIn {
AnimalOut animal();
}
public interface CatIn {
CatOut cat();
}
public interface MeowIn {
CatOut meow();
}
public interface DogIn {
DogOut dog();
}
public interface BarkIn {
DogOut bark();
}
public interface ChacesCarIn {
DogOut chacesCar();
}
public interface FindsHumanIn<T> {
HumanOut<T> findsHuman();
}
public interface HumanIn {
HumanOut<FarmOut> human();
}
public interface SaysHelloIn<T> {
HumanOut<T> saysHello();
}
public interface DoneIn<T> {
T done();
}
You may need to have multiple methods in an interface, but I haven't met this need yet. For example, if you had had to kinds of meows:
public interface MeowIn {
CatOut meowForFood();
CatOut meowForMilk();
CatOut meowForStrokes();
}
Define the output types:
Farm provides Animal or Human:
public interface FarmOut extends AnimalIn, HumanIn {
// no specific methods
}
Animal provides Cat, Dog or Done:
public interface AnimalOut extends CatIn, DogIn, DoneIn<FarmOut> {
// no specific methods
}
Cat provides Meow, FindsHuman or Done:
public interface CatOut extends MeowIn, FindsHumanIn<CatOut>, DoneIn<AnimalOut> {
// no specific methods
}
Dog provides Bark, ChacesCar, FindsHuman or Done:
public interface DogOut extends BarkIn, ChacesCarIn, FindsHumanIn<DogOut>, DoneIn<AnimalOut> {
// no specific methods
}
Human provides SayHello or Done:
public interface HumanOut<T> extends SaysHelloIn<T>, DoneIn<T> {
// no specific methods
}
Simply implement the *Out interfaces:
public class Farm implements FarmOut {
#Override
public AnimalOut animal() {
return new Animal(this);
}
#Override
public HumanOut<FarmOut> human() {
return new Human<FarmOut>(this);
}
}
public class Animal implements AnimalOut {
private FarmOut chain;
public Animal(FarmOut chain) {
this.chain = chain;
}
#Override
public CatOut cat() {
return new Cat(this);
}
#Override
public DogOut dog() {
return new Dog(this);
}
#Override
public FarmOut done() {
return chain;
}
}
public class Dog implements DogOut {
private AnimalOut chain;
public Dog(AnimalOut chain) {
this.chain = chain;
}
#Override
public DogOut bark() {
System.out.println("bark");
return this;
}
#Override
public DogOut chacesCar() {
System.out.println("chaces car");
return this;
}
#Override
public HumanOut<DogOut> findsHuman() {
return new Human<DogOut>(this);
}
#Override
public AnimalOut done() {
return chain;
}
}
public class Cat implements CatOut {
private AnimalOut chain;
public Cat(AnimalOut chain) {
this.chain = chain;
}
#Override
public CatOut meow() {
System.out.println("meow");
return this;
}
#Override
public HumanOut<CatOut> findsHuman() {
return new Human<CatOut>(this);
}
#Override
public AnimalOut done() {
return chain;
}
}
public class Human<T> implements HumanOut<T> {
private T chain;
public Human(T chain) {
this.chain = chain;
}
#Override
public HumanOut<T> saysHello() {
System.out.println("hello");
return this;
}
#Override
public T done() {
return chain;
}
}
Those implementations would work also without the interfaces: remove the implements *Out, the #Overrides, and replace any *Out by * (e.g. AnimalOut by Animal). That said, it's easier to maintain with the interfaces: simply update them and fix your compilation errors. It's also easier to find DSL solutions with interfaces (as you can see), and they are sometimes simply necessary.
Demo:
new Farm()
.animal()
.cat()
.meow()
.findsHuman()
.saysHello()
.done()
.done()
.dog()
.bark()
.chacesCar()
.findsHuman()
.saysHello()
.done()
.done()
.done()
.human()
.saysHello()
.done();
Prints:
meow
hello
bark
chaces car
hello
hello

Your problem is that the method done should return the parent, but the parent is not necessarily a T but is just a Base. And the other problem is that whatever the class is, the done method should always return the same class.
But here is a slight variation of your proposed classes. First for Base declaring its concrete class and its concrete parent :
abstract class Base<T extends Base<T, P>, P>{
private P parent;
Base(){
}
Base( P parent ){
this.parent = parent;
}
public P done() throws NullPointerException{
if ( parent != null ){
return parent;
}
throw new NullPointerException();
}
}
That being done, the derived concrete classes become :
class Farm extends Base<Farm, Object>{
private Animal animal;
private Human human;
public Farm(){
super();
this.animal = new Animal( this );
this.human = new Human( this );
}
public Animal animal(){
return this.animal;
}
public Human human(){
return this.human;
}
}
class Animal extends Base<Animal, Farm>{
private Cat cat;
private Dog dog;
public Animal(){
super();
init();
}
public Animal( Farm parent ){
super( parent );
init();
}
private void init(){
this.cat = new Cat(this);
this.dog = new Dog(this);
}
public Cat cat(){
return cat;
}
public Dog dog(){
return dog;
}
}
class Human extends Base<Human, Farm>{
public Human() {
}
public Human(Farm farm) {
super(farm);
}
public Human saysHello(){
System.out.println("human says hi");
return this;
}
}
class CatOrDog extends Base<Cat, Animal>{
protected Human human;
public CatOrDog(){
super();
init(null);
}
public CatOrDog( Animal parent ){
super( parent );
init(parent);
}
private void init(Animal parent){
Animal parent = done();
Farm farm = (parent == null) ? null : parent.done();
this.human = new Human(farm);
}
public Human findsHuman(){
return this.human;
}
}
class Cat extends CatOrDog{
public Cat(){
super();
}
public Cat( Animal parent ){
super( parent );
}
public Cat meow(){
System.out.println("cat says meow");
return this;
}
}
class Dog extends CatOrDog {
public Dog(){
super();
}
public Dog( Animal parent ){
super( parent );
}
public Dog bark(){
System.out.println("dog says woof");
return this;
}
public Dog chacesCar(){
System.out.println("cat drinks milk");
return this;
}
}
With that, I could write without any error or warning :
Farm farm = new Farm();
farm.animal()
.cat()
.meow()
.findsHuman()
.saysHello()
.done()
.animal()
.dog()
.bark()
.chacesCar()
.findsHuman()
.saysHello()
.done()
.animal()
.done()
.human()
.saysHello()
.done();
But note that I had to replace to done calls with animals calls.
Edit :
I added a new class CatOrDog to factorize the Human processing. As the parent of a Human is a Farm, I initialize the new human with a correct parent if it exists. That way, not only the above sources compiles without error or warning, but it also runs without any problem and it prints :
cat says meow
human says hi
dog says woof
cat drinks milk
human says hi
human says hi

There is no "safe" way to do this, but this should compile:
class Dog extends Base{
<T extends Dog> T bark(){
return (T) this;
}
}

Related

Create a generic method with generic signature

i have some redundant code that i would like to remove, my goal would be to create a method of this kind:
private GenericClass myMethod(GenericClass genericClass){
genericClass.getTipe(); //tipe1 or tipe2
genericClass.setValue("foo");
genericClass.setValue2("foo");
//some logic
return genericClass;
}
Where this method can pass two similar classes but which differ in the type of an attribute
public class Class1{
private Tipe1 tipe1;
private String value;
private String value2;
//Constructor,Getter and Setter
}
public class Class2{
private Tipe2 tipe2;
private String value;
private String value2;
//Constructor,Getter and Setter
}
What I would like to do is call the method
someServiceIml.myMethod ("Foo")
passing either an object of type Class1 or Class2 according to my needs, the business logic behind myMethod is practically the same.
This method i wish it was in the same implementation of a certain service, could you give me some solution?
Create a generic abstract type; either a super class or an interface:
public interface GenericClass<T> {
public T getTipe();
public void setValue(String s);
public void setValue2(String s);
}
Have your implementation classes implement it:
public class Class1 implements GenericClass<Tipe1> {
// leave implementation as is
}
public class Class2 implements GenericClass<Tipe2> {
// leave implementation as is
}
And type your method:
private <T> GenericClass<T> myMethod(GenericClass<T> genericClass){
T tipe = genericClass.getTipe();
genericClass.setValue("foo");
genericClass.setValue2("foo");
// some logic
return genericClass;
}
If Tipe1 and Tipe2 share a common type, you can type them too:
public interface GenericClass<T extends SomeTipe> {
public class MyClass {
public static void main(String args[]) {
Class1 c1 = new Class1();
Class2 c2 = new Class2();
GenericClass gc = myMethod(c1);
System.out.println(gc);
}
private static GenericClass myMethod(GenericClass genericClass){
genericClass.getTipe(); //tipe1 or tipe2
genericClass.setValue("foo");
genericClass.setValue2("foo");
//some logic
return genericClass;
}
}
class Class1 extends GenericClass<Tipe1>{
}
class Class2 extends GenericClass<Tipe2>{
}
class Tipe1 {
}
class Tipe2 {
}
class GenericClass<T> implements Tipe<T> {
private String value;
private String value2;
private T t;
public T getTipe() {
return t;
}
void setValue(String s) {
value = s;
}
void setValue2(String s) {
value2 = s;
}
}
interface Tipe<T> {
public T getTipe();
}
or you can cast to parent class like:
GenericClass gc = new Class2();

How to get the class of the genereric parameter of a Interface from the interface

I have this Interface:
public interface Test<T> {
default Class<?> getT() {
return T.getClass(); < --error
}
}
next i have a class that implements it:
static class ItemService implements Test<Item>{
}
And i want to get the 'Item' class from the 'ItemService' class
static ItemService service = new ItemService();
private static void k() {
System.out.println(service.getT());
}
Now one way to do it is this:
public interface Test<T> {
default Class<?> getT() {
return Type.type;
}
class Type {
public static Class<?> type;
}
}
Service:
static class ItemService implements Test<Item> {
public ItemService() {
Type.type = Item.class;
}
}
And it works fine but there is a problem,
When another class implement the interface:
static class OrderService implements Test<Order> {
public OrderService() {
Type.type = Order.class;
}
}
And i try:
static ItemService service = new ItemService();
static OrderService orderservice = new OrderService();
private static void k() {
System.out.println(service.getT());
}
I get the Order class and not the Item class
How can i make it work?
Classes inside interfaces are static, You can remove the default from the function and every class will need to implement this. example:
public interface Test<T> {
public Class<T> getT();
}
static class ItemService implements Test<Item> {
public Class<Item> getT() {return Item.class;}
}
static class OrderService implements Test<Order>{
public Class<Order> getT() {return Order.class;}
}
An alternative could be an abstract class.
public interface Test<T> {
public Class<T> getT();
}
abstract class AbstractTest<T> implements Test<T> {
private final Class<T> type;
AbstractItemService(Class<T> type) { this.type = type }
public Class<T> getT() {return type;}
}
class ItemService extends AbstractTest<Item> {
ItemService() { super(Item.class); }
// implement other things
}
class OrderService extends AbstractTest<Order>{
OrderService() { super(Order.class); }
// implement other things
}
Here is another option, if your implementation has an instance of T.
interface Test<T>{
T getT();
default Class<?> getClassOfT(){
return getT().getClass();
}
}

setParent(this) with Java generics

I have a generic Element class which contains elements of the same class. Based on that I would then create concrete classes like
Boxes extends Element<Boxes>
The point I don't get is the
setParent(this);
Why do I need to cast it
setParent((C) this);
(and suppress type casting warnings)? Obviously I am missing something...
How would you change the class to have no casting and no warnings?
I would argue that "this" is a Element object (at minimum) and C as well.
public class Element<C extends Element<C>> {
List<C> children;
C parent = null;
public Element() {
}
void setChildren(List<C> children) {
this.children = children;
for (C c : children) {
c.setParent((C) this); // warning, without the cast: error
}
}
void setParent(C parent) {
this.parent = parent;
}
You get this error because this is of type Element<C> and not of type C.
The following would work:
public class Element<C extends Element<C>> {
List<C> children;
Element<C> parent = null;
public Element() {
}
void setChildren(List<C> children) {
this.children = children;
for (C c : children) {
c.setParent(this);
}
}
void setParent(Element<C> parent) {
this.parent = parent;
}
}
Btw, IDEs are pretty good explaining why you get such errors.
Because nothing guarantees that this is of type C.
For example, you could create an object this way:
Element<Boxes> e = new Element<>();
or this way:
class Container extends Element<Boxes> {}
...
Container c = new Container();
You can add protected abstract C self() method to Element<C> class and use it instead of (C) this:
public abstract class Element<C extends Element<C>> {
List<C> children;
C parent = null;
protected abstract C self();
void setChildren(List<C> children) {
this.children = children;
for (C c : children) {
c.setParent(self());
}
}
void setParent(C parent) {
this.parent = parent;
}
}
Now when you extend Element<C> you can implement self() just by returning this:
public class Boxes extends Element<Boxes> {
#Override
protected Boxes self() {
return this;
}
}
This is a pretty popular design. You can see it, for example, if you delombok builders which are generated with Lombok #SuperBuilder annotation:
public class Example {
private final int someField;
protected Example(ExampleBuilder<?, ?> b) {
this.someField = b.someField;
}
public static ExampleBuilder<?, ?> builder() {
return new ExampleBuilderImpl();
}
public static abstract class ExampleBuilder<C extends Example, B extends ExampleBuilder<C, B>> {
private int someField;
public B someField(int someField) {
this.someField = someField;
return self();
}
protected abstract B self();
public abstract C build();
public String toString() {
return "Example.ExampleBuilder(someField=" + this.someField + ")";
}
}
private static final class ExampleBuilderImpl extends ExampleBuilder<Example, ExampleBuilderImpl> {
protected Example.ExampleBuilderImpl self() {
return this;
}
public Example build() {
return new Example(this);
}
}
}

How to instantiate an interface object?

I have an abstract class and several implementations.
Based on the implementation class, I'd like to execute a method and instantiate the implementation class itself with new constructor.
Of course the following won't work as the class is Abstract, and I cannot change this fact. But how could I pass the "logic" how to create each implementation object to the method prepareList()? Especially regarding design decisions.
abstract class AbstractClass {
int id;
String name;
int age;
//lots of fields
}
class FirstClass extends AbstractClass {
}
class SecondClass extends AbstractClass {
}
class MyService {
void execute(Data data) {
List<FirstClass> list = prepareList(data, FirstClass.class);
//process list
}
List<AbstractClass> prepareList(Data data, Class<? extends AbstractClass> clazz) {
List<AbstractClass> collection = new ArrayList<>();
for (Some value in data.getList()) {
AbstractClass obj = new AbstractClass(); //does of course not work with abstract class
obj.setId();
obj.setName();
obj.setAge();
collection.add(obj);
}
return collection;
}
}
abstract class Fruit { String name; int weight; }
class Apple extends Fruit {}
class Orange extends Fruit {}
class FruitFactory() {
public Fruit create(Data data) {
if ("apple" == data.getFruitName()) return new Apple();
else if ("orange" == data.getFruitName()) return new Orange();
else throw new UnsupportedOperationException();
}
}
class FruitService {
private FruitFactory factory = new FruitFactory();
void execute(Data data) {
List<Fruit> list = prepareList(data);
}
List<Fruit> prepareList(Data data) {
List<Fruit> fruits = new ArrayList<>();
for (Some value : data) {
Fruit fruit = factory.create(data);
// set fields
fruits.add(fruit);
}
return fruits;
}
}
Okay I have a suggestion why don't you do like
public class AbstractClass {
int id;
String name;
int age;
//lots of fields
}
class FirstClass extends AbstractClass{
}
class SecondClass extends AbstractClass{
}
class Data{
}
class Myservice{
void execute(Data data) {
List<FirstClass> list = prepareList(data, new FirstClass());//notice change
//process list
}
List<AbstractClass> prepareList(Data data, AbstractClass abstractClassObj) {
List<AbstractClass> collection = new ArrayList<>();
for (Some value in data.getList()) {
/* AbstractClass obj = new AbstractClass();*/ //does of course not work with abstract class
abstractClassObj.setId();
abstractClassObj.setName();
abstractClassObj.setAge();
collection.add(obj);
}
return collection;
}
}
BY this your object creation and logic will also remain at different places. It will also be helpful if in future you have another class extending abstract class
or you can have some factory and pass factory object to your method or service class and get instance in the method you want.
Sorry In a hurry I missed the loop thing with factory try some thing like
public class AbstractClass {
int id;
String name;
int age;
//lots of fields
}
class FirstClass extends AbstractClass{
}
class SecondClass extends AbstractClass{
}
class Factory{
public AbstractClass getInstance( Class<? extends AbstractClass> clazz){
if(clazz.getSimpleName().equals(FirstClass.class.getSimpleName())){
return new FirstClass();
}else {
return new SecondClass();
}
}
}
class Data{
}
class Myservice{
private final Factory factory;
public Myservice(Factory factory){
this.factory = factory;
}
void execute(Data data) {
List<FirstClass> list = prepareList(data, FirstClass.class);//notice change
//process list
}
List<AbstractClass> prepareList(Data data, Class<? extends AbstractClass> clazz) {
List<AbstractClass> collection = new ArrayList<>();
for (Some value in data.getList()) {
AbstractClass obj = factory.getInstance(clazz);
abstractClassObj.setId();
abstractClassObj.setName();
abstractClassObj.setAge();
collection.add(obj);
}
return collection;
}
}
Obviously you can modify example as per needs you can use enum sort of things. This is just basic example

Is it possible to use Enum constants as templates for instantiable classes in Java?

Sorry if my question is a bit unclear; I'm finding it a little tough to find the wording. I spent several hours screwing around in Eclipse, cruising the JavaDoc, and Google, as well as SO. I learned a lot, but didn't find an answer.
What I'd like to be able to do is define an Enum, eg.:
public enum Animals {
Cow,
Chicken,
Sheep,
Horse;
}
and have each enum constant define an instantiable class that's not a local class. Would the following work? And if not, why, and what would?
In some file:
abstract public class Animal {
private String nameString;
public String getName() {
return nameString;
}
}
In another:
public enum Animals {
Cow ((new Animal() {
private boolean hasMilk;
{
nameString = "Cow";
hasMilk = false;
}
public boolean hasMilk() {
return hasMilk;
}
}).getClass()),
Chicken ((new Animal() {
private boolean hasFeathers;
{
nameString = "Chicken";
hasFeathers = true;
}
public boolean hasFeathers() {
return hasFeathers;
}
}).getClass()),
Sheep ((new Animal() {
private boolean isShorn;
{
nameString = "Cow";
isShorn = false;
}
public boolean isShorn() {
return isShorn;
}
public void Shear() {
isShorn = true;
}
}).getClass()),
Horse ((new Animal() {
{
nameString = "Cow";
}
}).getClass());
private Class<? extends Animal> animalClass;
private Animals(Class<? extends Animal> a) {
animalClass = a;
}
public Class<? extends Animal> getAnimalClass() {
return animalClass;
}
}
And then, in some other method of some other class, be able to do this:
Animal farmAnimal;
farmAnimal = Animals.Sheep.getAnimalClass().newInstance();
boolean shorn = farmAnimal.isShorn();
(The value of shorn being false at this point);
farmAnimal.shear();
shorn = farmAnimal.isShorn();
(shorn == true)
farmAnimal = Animals.Sheep.getAnimalClass().newInstance();
shorn = farmAnimal.isShorn();
(shorn == false)
Obviously, this isn't the best way to do what I've done here, but that's not the point. I know I can specify behaviour for enum constants, but that doesn't make them multiply-instantiable as distinct instances. I want to be able to create multiple instances (or copies) of various enum constants, with different instance variables (and different quantities/types of instance variables), with different accessor methods, which I can then do stuff to (alter instance variables) without modifying the enum constant.
I get that enum constants are designed to be immutable. That doesn't clash with my idea; I want each enum constant to represent an immutable definition of a mutable class.
You can do something like this:
public enum AnimalType {
COW {
#Override
public Animal createNew() {
return new Cow();
}
},
HORSE {
#Override
public Animal createNew() {
return new Horse();
}
};
public abstract Animal createNew();
}
public abstract class Animal {
private final AnimalType type;
private final String nameString;
public Animal(final AnimalType type, final String nameString) {
super();
this.type = type;
this.nameString = nameString;
}
public String getName() {
return nameString;
}
public AnimalType getType() {
return type;
}
}
public class Horse extends Animal {
public Horse() {
super(AnimalType.HORSE, "Horse");
}
}
public class Cow extends Animal {
private boolean milk;
public Cow() {
super(AnimalType.COW, "Cow");
}
public boolean hasMilk() {
return milk;
}
public void setMilk(final boolean milk) {
this.milk = milk;
}
}
#Test
public void testEnum() {
Cow cow = (Cow) AnimalType.COW.createNew();
Horse horse = (Horse) AnimalType.HORSE.createNew();
System.out.println("cow : " + cow.getType() + ", has milk: " + cow.hasMilk());
System.out.println("horse: " + horse.getType());
}

Categories