I have an OOP approach to calculating a special code. There is a list of strategies that uses the chain of responsibility approach to calculate my value;
interface ChainStrategy {
Strategy getNext();
String getCode(SomeDto dto);
default String getDefaultVlue() {
return "";
};
}
class StrategyA implements ChainStrategy {
Strategy next;
StrategyA() {}
StrategyA(Strategy next) {
this.next = next;
}
Strategy getNext() {
return next;
}
public String getCode(SomeDto dto) {
if(dto.isA()) {
String result = dto.getA();
//this code could be placed in the abstract class to fulfill DRY
if(result == null) {
if(next!=null) {
result = next.getCode(dto);
}
else {
result = getDefaultVlue();
}
}
return result;
}
}
class StrategyB implements ChainStrategy {
// mostly the same code with different result calculation logic
}
class Client {
ChainStrategy strategy = new StrategyA(new StrategyB());
System.out.println(strategy.getCode())
}
}
This is "Java < 8" code that meets SOLID principles and can be easily tested. Usually, the real logic is more complicated than just dto.getA()
But it is just a chain of functions so I rewrite it:
interface ChainStrategy {
String getCode(SomeDto dto);
}
class CombineStrategy implements ChainStrategy {
private static final Function<SomeDto, Optional<String>> STRATEGY_A = dto -> Optional.of(dto).filter(SomeDto::isA).map(SomeDto::getA());
private static final Function<SomeDto, Optional<String>> STRATEGY_B = dto -> Optional.of(dto).filter(SomeDto::isB).map(SomeDto::getB());
private static final Function<SomeDto, String> STRATEGY_DEFAULT = dto -> "";
String getCode(SomeDto dto) {
Stream.of(STRATEGY_A, STRATEGY_B).map(st->st.apply(dto))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElseGet(() -> STRATEGY_DEFAULT.apply(dto));
}
}
And my questions:
This code has problems with a single responsibility and "open-close" principles. And I can't test my functions individually. But creating separate classes for my functions looks like an overhead. Do we need these principles in functional programming?
I can rewrite "String getCode" to another static function. And store all these functions as a static Util class. But I don't want to lose ability to dynamically substitute my ChainFunction in the runtime. How do people combine static functions and dynamic binding in functional languages?
Related
I want to dynamic search with Criteria API in Java.
In the code I wrote, we need to write each entity in the url bar in JSON. I don't want to write "plaka".
The URL : <localhost:8080/api/city/query?city=Ankara&plaka=> I want to only "city" or "plaka"
Here we need to write each entity, even if we are going to search with only 1 entity. Type Entity and it should be empty.
My code is as below. Suppose there is more than one entity, what I want to do is to search using a single entity it wants to search. As you can see in the photo, I don't want to write an entity that I don't need. can you help me what should I do?
My code in Repository
public interface CityRepository extends JpaRepository<City, Integer> , JpaSpecificationExecutor<City> {
}
My code in Service
#Service
public class CityServiceImp implements CityService{
private static final String CITY = "city";
private static final String PLAKA = "plaka";
#Override
public List<City> findCityByNameAndPlaka(String cityName, int plaka) {
GenericSpecification genericSpecification = new GenericSpecification<City>();
if (!cityName.equals("_"))
genericSpecification.add(new SearchCriteria(CITY,cityName, SearchOperation.EQUAL));
if (plaka != -1)
genericSpecification.add(new SearchCriteria(PLAKA,plaka, SearchOperation.EQUAL));
return cityDao.findAll(genericSpecification);
}
#Autowired
CityRepository cityDao;
My code in Controller
#RestController
#RequestMapping("api/city")
public class CityController {
#Autowired
private final CityService cityService;
public CityController(CityService cityService) {
this.cityService = cityService;
#GetMapping("/query")
public List<City> query(#RequestParam String city, #RequestParam String plaka){
String c = city;
int p;
if (city.length() == 0)
c = "_";
if (plaka.length() == 0) {
p = -1;
}
else
p = Integer.parseInt(plaka);
return cityService.findCityByNameAndPlaka(c,p);
}
My code in SearchCriteria
public class SearchCriteria {
private String key;
private Object value;
private SearchOperation operation;
public SearchCriteria(String key, Object value, SearchOperation operation) {
this.key = key;
this.value = value;
this.operation = operation;
}
public String getKey() {
return key;
}
public Object getValue() {
return value;
}
public SearchOperation getOperation() {
return operation;
}
My code in GenericSpecification
public class GenericSpecification<T> implements Specification<T> {
private List<SearchCriteria> list;
public GenericSpecification() {
this.list = new ArrayList<>();
}
public void add(SearchCriteria criteria){
list.add(criteria);
}
#Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = new ArrayList<>();
for (SearchCriteria criteria : list) {
if (criteria.getOperation().equals(SearchOperation.GREATER_THAN)) {
predicates.add(builder.greaterThan(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.LESS_THAN)) {
predicates.add(builder.lessThan(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.GREATER_THAN_EQUAL)) {
predicates.add(builder.greaterThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.LESS_THAN_EQUAL)) {
predicates.add(builder.lessThanOrEqualTo(
root.get(criteria.getKey()), criteria.getValue().toString()));
} else if (criteria.getOperation().equals(SearchOperation.NOT_EQUAL)) {
predicates.add(builder.notEqual(
root.get(criteria.getKey()), criteria.getValue()));
} else if (criteria.getOperation().equals(SearchOperation.EQUAL)) {
predicates.add(builder.equal(
root.get(criteria.getKey()), criteria.getValue()));
} else if (criteria.getOperation().equals(SearchOperation.MATCH)) {
predicates.add(builder.like(
builder.lower(root.get(criteria.getKey())),
"%" + criteria.getValue().toString().toLowerCase() + "%"));
} else if (criteria.getOperation().equals(SearchOperation.MATCH_END)) {
predicates.add(builder.like(
builder.lower(root.get(criteria.getKey())),
criteria.getValue().toString().toLowerCase() + "%"));
}
}
return builder.and(predicates.toArray(new Predicate[0]));
}
My code in SearchOperation
public enum SearchOperation {
GREATER_THAN,
LESS_THAN,
GREATER_THAN_EQUAL,
LESS_THAN_EQUAL,
NOT_EQUAL,
EQUAL,
MATCH,
MATCH_END,
}
The good thing about the Criteria API is that you can use the CriteriaBuilder to build complex SQL statements based on the fields that you have. You can combine multiple criteria fields using and and or statements with ease.
How I approached something similar int he past is using a GenericDao class that takes a Filter that has builders for the most common operations (equals, qualsIgnoreCase, lessThan, greaterThan and so on). I actually have something similar in an open-source project I started: https://gitlab.com/pazvanti/logaritmical/-/blob/master/app/data/dao/GenericDao.java
https://gitlab.com/pazvanti/logaritmical/-/blob/master/app/data/filter/JPAFilter.java
Next, the implicit DAO class extends this GenericDao and when I want to do an operation (ex: find a user with the provided username) and there I create a Filter.
Now, the magic is in the filter. This is the one that creates the Predicate.
In your request, you will receive something like this: field1=something&field2=somethingElse and so on. The value can be preceded by the '<' or '>' if you want smaller or greater and you initialize your filter with the values. If you can retrieve the parameters as a Map<String, String>, even better.
Now, for each field in the request, you create a predicate using the helper methods from the JPAFilter class and return he resulted Predicate. In the example below I assume that you don't have it as a Map, but as individual fields (it is easy to adapt the code for a Map):
public class SearchFilter extends JPAFilter {
private Optional<String> field1 = Optional.empty();
private Optional<String> field2 = Optional.empty();
#Override
public Predicate getPredicate(CriteriaBuilder criteriaBuilder, Root root) {
Predicate predicateField1 = field1.map(f -> equals(criteriaBuilder, root, "field1", f)).orElse(null);
Predicate predicateField2 = field2.map(f -> equals(criteriaBuilder, root, "field2", f)).orElse(null);
return andPredicateBuilder(criteriaBuilder, predicateField1, predicateField2);
}
}
Now, I have the fields as Optional since in this case I assumed that you have them as Optional in your request mapping (Spring has this) and I know it is a bit controversial to have Optional as input params, but in this case I think it is acceptable (more on this here: https://petrepopescu.tech/2021/10/an-argument-for-using-optional-as-input-parameters/)
The way the andPredicateBuilder() is made is that it works properly even if one of the supplied predicates is null. Also, I made s simple mapping function, adjust to include for < and >.
Now, in your DAO class, just supply the appropriate filter:
public class SearchDao extends GenericDAO {
public List<MyEntity> search(Filter filter) {
return get(filter);
}
}
Some adjustments need to be made (this is just starter code), like an easier way to initialize the filter (and doing this inside the DAO) and making sure that that the filter can only by applied for the specified entity (probably using generics, JPAFIlter<T> and having SearchFilter extends JPAFilter<MyEntity>). Also, some error handling can be added.
One disadvantage is that the fields have to match the variable names in your entity class.
I have a Car object that has several properties. Each of its properties are populated using a service (generally one property per service). Each of those services generally call a 3rd party web service (e.g. carClient) to get its data. Most of my services also have logic on how to populate its Car object field. For example:
#Service
#RequiredArgsConstructor
public class CarPriceService {
// client of a 3rd party web service interface
// I don't have control over this interface.
private final CarClient carClient;
public void setAutoPrice(Set<Car> cars) {
// in this case, only one call to the web service
// is needed. In some cases, I need to make two calls
// to get the data needed to set a Car property.
Map<String, BigDecimal> carPriceById =
carClient.getCarPrice(cars.stream().map(c->c.getId()).collect(Collector.toSet()));
for (Car car : cars) {
// in this case the poulating logic is simple
// but for other properties it's more complex
BigDecimal autoPrice = autoPriceById.get(car.getId());
car.setAutoPrice(autoPrice);
}
}
}
The order of populating the Car properties is sometimes important. For example, CarValueService sets car.value using car.condition which is set by CarConditionService.
Is there a design pattern that works for handling the gradual build of an object over services? I'm aware of the Builder pattern but not sure how it would apply here.
Some kind of Pipeline Pattern1, 2 variant comes to mind. For instance,
final class Test {
public static void main(String[] args) {
final Car car = new Car();
CarTransformer.of(c -> System.out.println("Install wheels!"))
.then(c -> System.out.println("Install engine!"))
.then(c -> System.out.println("Paint!"))
.transform(car);
}
static final class Car {}
static interface CarTransformer {
default CarTransformer then(final CarTransformer step) {
return (car) -> {
this.transform(car);
step.transform(car);
};
}
static CarTransformer of(final CarTransformer step) {
return step;
}
void transform(Car car);
}
}
Obviously you probably wouldn't inline all transformations, but you get the idea. Here we use function composition to create the pipeline, but you could also just store transformations in a list.
Furthermore, if building the transformation pipeline is complex, you could could add the builder pattern in the mix. E.g.
final class Test {
public static void main(String[] args) {
final Car car = new CarBuilder()
.installEngine("V8")
.installWheel("front-left")
.installWheel("rear-right")
.paint("metallic blue")
.build();
}
static final class Car {}
static interface CarTransformer {
default CarTransformer then(final CarTransformer step) {
return (car) -> {
this.transform(car);
step.transform(car);
};
}
static CarTransformer of(final CarTransformer step) {
return step;
}
void transform(Car car);
}
static final class CarBuilder {
private CarTransformer transformer;
CarBuilder() {
transformer = CarTransformer.of(c -> {});
}
CarBuilder paint(final String color) {
return then(c -> System.out.println("Paint in " + color));
}
CarBuilder installWheel(final String wheel) {
return then(c -> System.out.println("Install " + wheel + " wheel!"));
}
CarBuilder installEngine(final String engine) {
return then(c -> System.out.println("Install " + engine + " engine!"));
}
private CarBuilder then(final CarTransformer transformer) {
this.transformer = this.transformer.then(transformer);
return this;
}
Car build() {
final Car car = new Car();
transformer.transform(car);
return car;
}
}
}
Pipeline design pattern implementation
https://java-design-patterns.com/patterns/pipeline/
I have following code example (code below).
I have interfaces OnlyReverse and OnlySplit which define operations on class Data. I will sometimes have class available only for reversing and sometimes, I will be able to do reversing and splitting.
In the code I have 2 approaches.
1st approach is to use 2 separate classes for these 2 separate use-cases ReverseAndSplitImpl and OnlyReverseImpl. Here I do not like that I need additional class, and that I need to duplicate some of the code between those 2 classes.
2nd approach is to use 1 class for both use-cases SingleClassForReverseAndSplitImpl and then use strategy to inject either NormalSplit or NoSplit. Here I do not like this additional NoSplit class that is basically artificial one.
According to interface segregation principle - do I need to have ReverseAndSplit joining interface, or should I always use both interfaces separately (like SingleClassForReverseAndSplitImpl implements OnlyReverse, OnlySplit and not SingleClassForReverseAndSplitImpl implements ReverseAndSplit)?
Which approach of these is better in a long run (more flexible in the future)?
class Data{
String a;
}
interface OnlyReverse{
Data getData();
OnlyReverse reverse();
}
interface OnlySplit{
OnlySplit split();
}
interface ReverseAndSplit extends OnlyReverse, OnlySplit{
#Override
ReverseAndSplit reverse();
#Override
ReverseAndSplit split();
}
//------------------------- USE DISTINCT CLASSES; ONE HAS SPLIT OTHER NO
class ReverseAndSplitImpl implements ReverseAndSplit{
Data data;
public ReverseAndSplitImpl(Data data) {
this.data = data;
}
#Override
public Data getData() {
return data;
}
#Override
public ReverseAndSplit reverse() {
//here reverse and return
return new ReverseAndSplitImpl(data);
}
#Override
public ReverseAndSplit split() {
//here split and return
return new ReverseAndSplitImpl(data);
}
}
class OnlyReverseImpl implements OnlyReverse{
Data data;
public OnlyReverseImpl(Data data) {
this.data = data;
}
#Override
public Data getData() {
return data;
}
#Override
public OnlyReverse reverse() {
return new OnlyReverseImpl(data);
}
}
//------------------------- USE DISTINCT CLASSES; ONE HAS SPLIT OTHER NO
//------------------------- USE STRATEGY TO CHOOSE TO HAVE SPLITTING OR NO
interface SplitStrategy{
Data split(Data data);
}
class NormalSplit implements SplitStrategy{
#Override
public Data split(Data data) {
return new Data();
}
}
//NullObject pattern
class NoSplit implements SplitStrategy{
#Override
public Data split(Data data) {
return data;
}
}
class SingleClassForReverseAndSplitImpl implements ReverseAndSplit{
Data data;
SplitStrategy splitStrategy;
public SingleClassForReverseAndSplitImpl(Data data, SplitStrategy splitStrategy) {
this.data = data;
this.splitStrategy = splitStrategy;
}
#Override
public Data getData() {
return data;
}
#Override
public ReverseAndSplit reverse() {
//here reverse and return
return new SingleClassForReverseAndSplitImpl(data, splitStrategy);
}
#Override
public ReverseAndSplit split() {
//here split and return
SingleClassForReverseAndSplitImpl s = new SingleClassForReverseAndSplitImpl(data, splitStrategy);
s.data = splitStrategy.split(data);
return s;
}
}
//------------------------- USE STRATEGY TO CHOOSE TO HAVE SPLITTING OR NO
public class Decorator {
public static void main(String[] args) {
ReverseAndSplit s11 = new SingleClassForReverseAndSplitImpl(new Data(), new NoSplit());
s11 = s11.reverse();
s11 = s11.split(); //has split operation, but NoSplit will do nothing
OnlyReverse s12 = new OnlyReverseImpl(new Data());
s12 = s12.reverse();
//has no split operation present
//Going from NoSplit to SplitAndReverse
ReverseAndSplit s21 = new SingleClassForReverseAndSplitImpl(s11.getData(), new NormalSplit());
s21 = s21.reverse();
s21 = s21.split(); //has split and now it is using NormalSplit
ReverseAndSplit s22 = new ReverseAndSplitImpl(s12.getData());
s22 = s22.reverse();
s22 = s22.split();
}
}
I guess it's reasonable to use your first approach (two simpler interfaces) but to not call them OnlyReverse and OnlySplit but Reverse and Split. So it's reasonable to combine them and in future you can also just use one of them.
But it's also depending on your domain objects, so it's hard to make a choice for you. But I would not create an interface called NoSplit because you could still implement ReverseAndSplit and NoSplit which would make no sense for you.
According to the Interface Segregation Principle, if you have a client who never splits, then you should not present that client with an interface including a split method. The Strategy / Null Object approach is suitable for a single client who sometimes requires splitting and other times does not. The separate interfaces approach is suitable for two different clients who have different requirements.
I have multiple Optionals that must be mapped to a POJO. Is there a better alternative than the following?
class SimplePojo {
private String stringField;
private Integer integerField;
// All args. constructor, getter, setter
}
Optional<String> stringOptional = ...
Optional<Integer> integerOptional = ...
Optional<SimplePojo> simplePojoOptional = stringOptional.flatMap(
string -> integerOptional.map(integer -> new SimplePojo(string, integer)))
I have reduced the problem to 2 Optionals in the above example to keep it short. But I actually have 3 Optionals with more on the way. I am afraid the last line can easily become unwieldy soon.
Please note: Use of functional frameworks like Vavr or Functional Java is not an option for me.
How about using a Builder ?
class SimplePojo {
public static class Builder {
private String stringField;
public Builder withStringField(String str) {
this.stringField = str;
return this;
}
// and other "with" methods...
public Optional<SimplePojo> build() {
if (stringField == null || anotherField == null /* and so forth */) {
return Optional.empty();
} else {
return Optional.of(new SimplePojo(this));
}
}
}
private final String stringField;
/* private constructor, so client code has to go through the Builder */
private SimplePojo(Builder builder) {
this.stringField = builder.stringField;
// etc.
}
}
Then you could use it as follows:
SimplePojo.Builder builder = new SimplePojo.builder();
optionalStringField.ifPresent(builder::withStringField);
// etc.
return builder.build();
I do not see any advantage from pursuing the functional style this way here. see three options:
ONE: If you can alter the SimplePojo class and if this scenario is a common one, you might consider to add a factory method to the SimplePojo:
class SimplePojo {
public static Optional<SimplePojo> of(final Optional<String> stringField, final Optional<Integer> integerField) {
if (stringField.isPresent() && integerField.isPresent()) {
return new SimplePojo(stringField.get(), integerField.get());
else
return Optional.empty();
}
}
TWO: If you cannot alter the SimplePojo, you might want to create this as a utility method somewhere else. If you need this pattern only in one class, make the method private in this class!
THREE: If you need to do this only once or twice, I would prefer the if...then construction from the first option over the functional notation you used for the sake of readability:
final Optional<SimplePojo> simplePojoOptional;
if (stringField.isPresent() && integerField.isPresent()) {
simplePojoOptional = new SimplePojo(stringField.get(), integerField.get());
else
simplePojoOptional = Optional.empty();
We are using the builder pattern to create some input for service, and it looks like something like this (simplified):
final SomeInput input = SomeInput.builder()
.withSomeId(....)
.withSomeState(....)
...
.build();
There's some attribute that we want to set in SomeInput, but only if it is present. So after creating the object, I do something like this:
Optional<String> secondaryId = infoProvider.getSecondaryId();
if (secondaryId.isPresent()) {
input.setSecondaryId(secondaryId.get());
}
I was wondering:
a) Is there a better/cleaner way to do this?
b) If I do need to do it this way, can I avoid the "if" statement and utilize some functionality with Optional?
(Note: I cannot change the builder itself, and I cannot that the secondaryId is a String, but that what we retrieve from infoProvider is an optional)
A little bit cleaner would be to use ifPresent
secondaryId.ifPresent(input::setSecondaryId);
but that's pretty much the best you can get with these requirements.
I was just facing the same problem as the OP and came up with this abstraction, which integrates directly with the builder instead of later modifying the object via setters. It would work the same with a model that instead of builders just offers "wither" methods.
(using lombok)
#RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class Modifier<T> {
private final T value;
public static <T> Modifier<T> modify(T initialValue) {
return new Modifier<>(initialValue);
}
public <U> Modifier<T> ifPresent(Optional<U> optional, BiFunction<T, U, T> modifier) {
return modify(optional.map(input -> modifier.apply(value, input)).orElse(value));
}
public T get() {
return value;
}
}
Applied to the OP's example this would be used like this (again using lombok for generating the builder):
import static Modifier.modify;
import static org.junit.Assert.assertEquals;
class ModifierTest {
#Value
#Builder
static class SomeInput {
String id;
String secondaryId;
String state;
}
SomeInput constructSomeInput(Optional<String> maybeSecondaryId, Optional<String> maybeState) {
final SomeInput result = modify(SomeInput.builder().id("myId"))
.ifPresent(maybeSecondaryId, (builder, secondaryId) -> builder.secondaryId(secondaryId))
.ifPresent(maybeState, (builder, state) -> builder.state(state))
.get()
.build();
return result;
}
#Test
public void shouldBuildSomeInputWithSecondaryId() {
final Optional<String> maybeSecondaryId = Optional.of("mySecondaryId");
final Optional<String> maybeState = Optional.of("myState");
final SomeInput result = constructSomeInput(maybeSecondaryId, maybeState);
assertEquals("mySecondaryId", result.getSecondaryId());
assertEquals("myState", result.getState());
}
#Test
public void shouldBuildSomeInputWithoutSecondaryId() {
final Optional<String> maybeSecondaryId = Optional.empty();
final Optional<String> maybeState = Optional.of("myState");
final SomeInput result = constructSomeInput(maybeSecondaryId, maybeState);
assertEquals(null, result.getSecondaryId());
assertEquals("myState", result.getState());
}
}