How to organize and test code in functional style in Java

Viewed 60

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:

  1. 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?
  2. 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?
0 Answers
Related