Reputation: 150
I have come across with this design and I didn't fully grasp mixing object oriented programming with functional programming in Java 8.
I was interested in mixing both language paradigms and most of the tutorials in the internet are about simple, so I wasn't be able to find a sample about large-scale software design by mixing them. So with this sample case I think I had an opportunity to dig it for some cases of it.
Let me show the related parts of the code in this case. This code contains a generic FetchUtils class which implements a custom iterator, but for the sake of brevity I have removed some parts.
public class FetchUtils<R, MSGIN, MSGOUT> {
public SomeClass<R> getSomething(MSGIN query,
Function<MSGIN, MSGOUT> queryFunc,
Function<MSGOUT, List<R>> getResultList) {
//...
MSGOUT callResult = queryFunc.apply(query);
buffer = getResultList.apply(callResult);
//...
//return someThing;
}
//...
}
In the client there are a Function defined and a lambda expression pointing a reference to getCustomer
method of a class. Actual call from the client to above method which is using generic types is sending these functionals.
public class CustomerResponse {
//...
public List<Customer> getCustomer() {
if (thing == null) {
thing = new ArrayList<Customer>();
}
return this.customers;
}
//...
}
public class MyClient {
//...
@Autowired
private FetchUtils<Customer, CustomerRequest, CustomerResponse> fetchUtils;
//...
public SomeClass<Customer> fetch() {
//...
Function<CustomerRequest, CustomerResponse> requestFunc = q -> {
try {
return myService.doSomething(q);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
};
CustomerRequest query = new CustomerRequest(/*...*/);
return fetchUtils.getSomething(query,
requestFunc,
r -> r.getCustomer());
//...
}
//...
}
How do you rewrite this code only using object oriented programming i.e. without passing higher order functions and only using dynamic dispatch or even without generics?
Would this design be possible without generics?
How type inference works here with these generic types and functionals?
Is this design a possible example of mixing functional and object oriented programming or how do you evaluate this design?
Upvotes: 5
Views: 491
Reputation: 31888
If my understanding of your question is correct, by higher-order functions you mean the Function
that you have been passing to the getSomething
method in your code.
One way of thinking around that could be to simply represent classes abstract
assigning each one of them their defined role. In an example, the following code does the same evaluation as in the code-shared by you but assigning different roles to respective individual classes.
abstract class Transform<I, O> {
abstract O queryFunction(I input);
}
abstract class Group<O, R> {
abstract List<R> groupIntoResult(O output);
}
abstract class FetchUtil<R, I, O> {
Group<O, R> group;
Transform<I, O> transform;
public SomeClass<R> getSomething(I input) {
O output = transform.queryFunction(input);
List<R> grouped = group.groupIntoResult(transform.queryFunction(input));
return new SomeClass<>(grouped);
}
}
No doubt you can transform these into an interface
as well depending upon the usage of these APIs. That is where the initial code you had was closer to actually making use of a FunctionalInterface
class named Function
.
To answer further, these representations without being generic can be extended easily to provide a customer-specific implementation in the following manner
class Transformer extends Transform<CustomerRequest, CustomerResponse> {
@AutoWired
MySerice myService;
@Override
CustomerResponse queryFunction(CustomerRequest input) {
try {
return myService.doSomething(input);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
class Grouping extends Group<CustomerResponse, Customer> {
@Override
List<Customer> groupIntoResult(CustomerResponse output) {
return output.getCustomer();
}
}
Note the simplification of tasks for your client with the FetchUtil
definition now. It only needs to provide the request object and you an bind the transforming and grouping implementation to the utility class you've written to turnaround with a response.
Your client code cuts short to eventually the following lines and you can notice how this off burdens the clients consuming your sevices:
public class MyClient {
@AutoWired
private FetchUtil<Customer, CustomerRequest, CustomerResponse> fetchUtil;
// bind the above to appropriate Group and Transform implementation
public SomeClass<Customer> fetch() {
CustomerRequest query = new CustomerRequest(/*...*/);
return fetchUtil.getSomething(query);
}
}
Upvotes: 4
Reputation: 36401
How do you rewrite this code only using object oriented programming i.e. without passing higher order functions and only using dynamic dispatch or even without generics?
class FuncImpl implements Function<CustomerRequest, CustomerResponse> {
public CustomerResponse apply(CustomerResquest q) {
try {
return myService.doSomething(q);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
Function<CustomerRequest, CustomerResponse> requestFunc = new FuncImpl();
class FuncImpl2 implements Function<CustomerResponse,List<Customer>> {
public List<Customer> apply(CustomerResponse r) {
return r.getCustomer();
}
}
...
return fetchUtils.getSomething(query, requestFunc,new FuncImpl2());
Would this design be possible without generics?
Of course, enforce the concrete type everywhere. (See below type deduction and make it by hand...).
How type inference works here with these generic types and functionals?
Generics parameters are just type variables, so your example is very easy to understand.
requestFun
has type Function<CustomerRequest, CustomerResponse>
then compiler can easily deduce that MSGIN
is CustomerRequest
and MSGOUT
CustomerResponse
.
For r -> r.getCustomer()
compiler already knows that MSGOUT
is CustomerResponse
then it looks at CustomerResponse
type and find that getCustomer
returns a List<Customer>
thus the lambda has type Function<CustomerResponse,List<Customer>>
and then R
is List<Customer>
Is this design a possible example of mixing functional and object oriented programming or how do you evaluate this design?
Yes it is a good example.
Upvotes: 6