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
Related
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();
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();
}
}
I'm trying to return an array list of the subclass object
Suppose
abstract class Foo {
protected abstract ArrayList<Foo> getAlotOfMyself();
};
Is a super class where it's sub-classes need to return an array of themselves,
for example it's sub-class:
class Bar extends Foo{
public ArrayList<Bar> getAlotOfMyself(){
// Do the interesting stuff
}
};
However this doesn't work because of java, ArrayList<Foo> is not the same type as ArrayList<Bar> even if Bar is a subclass of Foo
I've tried changing the ArrayList in Foo to ArrayList<? extends Foo> but it seems to only work as long as Foo is not an abstract class (and therefore getAlotOfMyself() is implemented in Foo), it doesn't compile saying :
cannot convert from ArrayList<capture#1-of ? extends Foo> to ArrayList<Foo>.
The reason the causes that error is this
void interestingFunction(Foo foo){
ArrayList<Foo> alot = foo.getAlotOfMyself(); // the compile error happens here
}
and of course this function is only called on Bar and other sub-classes
Try this and see if it does what you want.
import java.util.ArrayList;
import java.util.List;
public class SubclassStuff {
public static void main(String[] args) {
Bar b = new Bar();
b.interestingFunction(b);
}
}
abstract class Foo {
public String name;
public Foo() {
}
public Foo (String name) {
this.name = name;
}
protected abstract ArrayList<? extends Foo> getAlotOfMyself();
public void interestingFunction(Foo foo) {
System.out.println(foo.getAlotOfMyself());
}
}
class Bar extends Foo {
public ArrayList<Bar> getAlotOfMyself() {
return new ArrayList<>(List.of(new Bar("I am Bar")));
}
public Bar() {
super();
}
public Bar (String name) {
this.name = name;
}
public String toString() {
return name;
}
}
I'm trying to prepare an interface i want to implement for Datamodel-Classes.Therefor i want to use an enum inside the interface so i know i need to implement it later.
Example:
public interface MyModelInterface {
public enum Field;
public Object get(Field field);
public void set(Field field, Object value);
}
The expected implementation:
public class MyModel implements MyModelInterface {
public enum Field {
ID("id"),
Name1("Name1"),
Name2("Name2");
private String field;
private Field(String field) {
this.field = field;
}
}
public Object get(Field field) {
//...
}
public void set(Field field, Object value){
//...
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get(MyModel.Field.ID));
System.out.println(myModel.get(MyModel.Field.Name1));
}
}
Since I don't know which fields the model will contain until I implement it.
I did some research and figured that enum can't be extended, so i am aware of that.
is there any way to archive this or any kind of workaround?
i don't want to use String Parameters on the getter/setter Methods to avoid using wrong values.
Thanks in advance for any suggestion.
Update:
So this is what worked for me: Splitting the interface/class in three parts, including an abstract class:
Interface:
public interface MyModelInterface<E extends Enum<E>> {
public Object get(E field);
public void set(E field, Object value);
}
Abstract Class:
public abstract class MyAbstractModel<E extends Enum<E>> implements MyModelInterface<E>{
protected final EnumMap<E, Object> fields;
public MyAbstractModel(Class<E> enumKlazz) {
fields = new EnumMap<>(enumKlazz);
}
#Override
public Object get(E field) {
return fields.get(field);
}
#Override
public void set(E field, Object value) {
this.fields.put(field, value);
}
}
Class(where i actually archive my goal):
public class MyModel extends MyAbstractModel<MyModel.Field> {
public MyModel() {
super(MyModel.Field.class);
}
public enum Field {
ID("ID"),
Name1("NAME1"),
Name2("NAME2"),
Age("AGE"),
;
private final String field;
private Field(String field) {
this.field = field;
}
public String getName() {
return field;
}
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get(Field.Name1));
}
}
Interface fields are static and final implicitly.
What you could do is to have an interface method returning Enum<?>, and your classes implementing it.
For instance:
interface Foo {
public Enum<?> getEnum();
}
class Bar implements Foo {
enum Blah {
INSTANCE;
}
public Enum<?> getEnum() {
return Blah.INSTANCE;
}
}
Edit
Not completely sure I understand your question update, but here's a solution that will de-couple returning a specific enum instance from an enum, by means of two interfaces.
The example is self-contained in a Main class.
public class Main {
public static void main(String[] args) {
System.out.println(new Bar().getEnumField().name());
}
static interface IHasEnum {
public Enum<? extends IMyEnum> getEnumField();
}
static interface IMyEnum {
public Enum<? extends IMyEnum> getField();
}
static class Bar implements IHasEnum {
enum Blah implements IMyEnum {
DEFAULT_INSTANCE,
THE_FIELD;
public Enum<? extends IMyEnum> getField() {
return THE_FIELD;
}
}
public Enum<? extends IMyEnum> getEnumField() {
return Blah.DEFAULT_INSTANCE.getField();
}
}
}
Output
THE_FIELD
Note
The trick here is to add a "default" instance to the enum (DEFAULT_INSTANCE), so the getField method is an instance method, hence overriding the one declared in the IMyEnum interface.
Again, not entirely sure this addresses your issue.
What you are describing is an EnumMap<E, T> - which functions like an array, with that same get-
public class MyModelBase<E extends Enum<E>> {
private final Class<E> enumKlazz;
private final EnumMap<E, Object> fields;
public MyModelBase(Class<E> enumKlazz) {
this.enumKlazz = enumKlazz;
fields = new EnumMpa<>(enumKlazz);
}
public Object get(E field) {
return fields.get(field);
}
public void set(E field, Object value) {
fields.put(field, value);
}
}
enum UserField { id, surname, name, age };
MyModelBase<UserField> userModel = new MyModelBase<>(UserField.class);
userModel.set(UserField.surname, "X");
Because of type erasure the enum map needs the class. Above the enum class is also stored as field, as some static Enum methods need the enum class. For iterating, and so on.
Java generics will be the best solution.
Lets assume, you don't know the contents of the Field as mentioned.
Create a generic interface like this:
public interface MyModelInterface<T> {
public T get();
}
Then create a class Field like this:
public class Field {
private String id;
private String name1;
private String name2;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
}
and then your model class will look like
public class MyModel implements MyModelInterface<Field> {
#Override
public Field get() {
Field field = new Field();
field.setId("ID");
field.setName1("Name1");
field.setName2("Name2");
return field;
}
public static void main(String[] args) {
MyModel myModel = new MyModel();
System.out.println(myModel.get().getId());
System.out.println(myModel.get().getName1());
System.out.println(myModel.get().getName2());
}
}
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;
}
}