I would like to implement something like Strategy Pattern. I have generalized logic in Parent method, I need to pass specific logic (with casting etc..) into parent.
I have following classes:
class A{
public Object generateData(Function fetchData, AbstractForm form)
{
List<DataBean> dataBeans = (List<DataBean>) fetchData.apply(form);
//...
}
}
class B extends A{
void someMethod(AbstractForm form){
Function<AbstractForm, List<DataBean>> fetchFunction = new Function<AbstractForm, List<DataBean>>() {
//here goes form specific casting and other data fetch specific logic
return dataBeans;
}
super.generateData(fetchFunction, form);
}
}
Did I get the Idea of function correctly here?
Correct use of the Strategy pattern implies aggregation between a Context (in your case class A
) and a Strategy (in your case an implementation of Function
).
You can see the relationship in the image below (taken from the Gang of Four book, Design patterns: elements of reusable object-oriented software).
Below I've applied a traditional Strategy pattern approach to your problem. In this case I've made it so that Function.apply(AbstractForm)
returns List<DataBean>
to remove the need for casting. You could of course use generics to make Function
more flexible.
Strategy
public interface Function {
List<DataBean> apply(AbstractForm form);
}
Context
public class A {
private Function fetchData; // strategy
public void setStrategy(Function fetchData) { // method for setting the strategy
this.fetchData = fetchData;
}
// precondition: fetchData != null
public Object generateData(AbstractForm form) {
List<DataBean> dataBeans = fetchData.apply(form); // using the strategy
return null; // whatever you want to return
}
}
In this case, extending class A
is not neccessary as we can inject our Strategy (Function
) using setStrategy(Function)
. However, we could always extend A
to great an object with a predefined Strategy.
For example:
public class B extends A {
public B() {
setStrategy((form) -> null); // implement your concrete strategy here
}
}
Using a Factory Method
Since a Strategy for fetching the data is likely required and there may be no 'default' to use and may not ever change, the Factory method pattern could be used instead to enforce the creation of a Product (Function
). Note class A
is now abstract and includes a Factory method createFunction()
which is then implemented in the subclasses (e.g. B
) to create the Function
.
The design for the factory method pattern can be seen in the UML below. In this case our Product is now what was previously our Strategy (Function
) and the Creator is class A
, with the ConcreteCreator being class B
.
Creator
public abstract class A {
private Function fetchData; // product to be used
public class A() {
fetchData = createFunction(); // call factory method
}
protected abstract Function createFunction(); // factory method
// precondition: fetchData != null
public Object generateData(AbstractForm form) {
List<DataBean> dataBeans = fetchData.apply(form); // using the product
return null; // whatever you want to return
}
}
ConcreteCreator
public class B extends A {
@Override
protected Function createFunction() {
return (form) -> null; // return product
}
}
In this case the Product is fixed and not changable, but this could be overcome by mixing the two patterns together and including setStrategy(Function)
again from class A
in the first example.