Scala : Registry design pattern or similar? - java

I am migrating my system from java to Scala. I have used registry pattern in my java code to get the implementation from the string. Is there any similar thing I could do with scala ? I am new to scala, can someone point to me proper references ?
My java code :
public class ItemRegistry {
private final Map<String, ItemFactory> factoryRegistry;
public ItemRegistry() {
this.factoryRegistry = new HashMap<>();
}
public ItemRegistry(List<ItemFactory> factories) {
factoryRegistry = new HashMap<>();
for (ItemFactory factory : factories) {
registerFactory(factory);
}
}
public void registerFactory(ItemFactory factory) {
Set<String> aliases = factory.getRegisteredItems();
for (String alias : aliases) {
factoryRegistry.put(alias, factory);
}
}
public Item newInstance(String itemName) throws ItemException {
ItemFactory factory = factoryRegistry.get(itemName);
if (factory == null) {
throw new ItemException("Unable to find factory containing alias " + itemName);
}
return factory.getItem(itemName);
}
public Set<String> getRegisteredAliases() {
return factoryRegistry.keySet();
}
}
My Item interface :
public interface Item {
void apply(Order Order) throws ItemException;
String getItemName();
}
I map the string like :
public interface ItemFactory {
Item getItem(String itemName) throws ItemException;
Set<String> getRegisteredItems();
}
public abstract class AbstractItemFactory implements ItemFactory {
protected final Map<String, Supplier<Item>> factory = Maps.newHashMap();
#Override
public Item getItem(String alias) throws ItemException {
try {
final Supplier<Item> supplier = factory.get(alias);
return supplier.get();
} catch (Exception e) {
throw new ItemException("Unable to create instance of " + alias, e);
}
}
protected Supplier<Item> defaultSupplier(Class<? extends Item> itemClass) {
return () -> {
try {
return itemClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException("Unable to create instance of " + itemClass, e);
}
};
}
#Override
public Set<String> getRegisteredItems() {
return factory.keySet();
}
}
public class GenericItemFactory extends AbstractItemFactory {
public GenericItemFactory() {
factory.put("reducedPriceItem", () -> new Discount(reducedPriceItem));
factory.put("salePriceItem", () -> new Sale(reducedPriceItem));
}
}
where Sale and Discount are implemntation of Item. I use the newInstance method in ItemRegistry to get the class based on the name. Can some one suggest me any similar thing which can allow me to do the same in scala ?

The other answers give the following options:
Directly translate your existing Java code to Scala.
Implement another version of your existing code in Scala.
Use Spring for dependency injection.
This answer offers an approach that is different from the "registry pattern" and that uses the compiler instead of a string, or Spring, to resolve implementations. In Scala, we can use the language constructs to inject dependencies with the cake pattern. Below is an example using simplified versions of your classes:
case class Order(id: Int)
trait Item {
// renamed to applyOrder to disambiguate it from apply(), which has special use in Scala
def applyOrder(order: Order): Unit
def name: String
}
trait Sale extends Item {
override def applyOrder(order: Order): Unit = println(s"sale on order[${order.id}]")
override def name: String = "sale"
}
trait Discount extends Item {
override def applyOrder(order: Order): Unit = println(s"discount on order[${order.id}]")
override def name: String = "discount"
}
Let's define a class Shopping that depends on an Item. We can express this dependency as a self type:
class Shopping { this: Item =>
def shop(order: Order): Unit = {
println(s"shopping with $name")
applyOrder(order)
}
}
Shopping has a single method, shop, that calls both the applyOrder and name methods on its Item. Let's create two instances of Shopping: one that has a Sale item and one that has a Discount item...
val sale = new Shopping with Sale
val discount = new Shopping with Discount
...and invoke their respective shop methods:
val order1 = new Order(123)
sale.shop(order1)
// prints:
// shopping with sale
// sale on order[123]
val order2 = new Order(456)
discount.shop(order2)
// prints:
// shopping with discount
// discount on order[456]
The compiler requires us to mix in an Item implementation when creating a Shopping instance. We have compile-time enforcement of the dependencies, and we don't need third-party libraries, with this pattern.

You can pretty much just translate your Java classes to Scala and use the exact same pattern as you're doing in Java.
Since Scala runs on the JVM you can also use it with Spring. It may not be the "standard" way of writing services in Scala but it's definitely a viable choice.

As others have already suggested, you can translate your code directly into Scala without changing the design pattern, if that's what you want.
Here's how that might look:
import scala.collection.Set
import scala.collection.mutable
import scala.collection.immutable
trait Item
trait ItemFactory {
def registeredItems: Set[String]
def getItem(alias: String): Item
}
class ItemRegistry(factories: List[ItemFactory]) {
final private val factoryRegistry = mutable.Map[String, ItemFactory]()
factories.foreach(this.registerFactory)
def registerFactory(factory: ItemFactory): Unit = {
factory.registeredItems.foreach(alias =>
factoryRegistry.put(alias, factory))
}
def newInstance(itemName: String): Item = {
val factory = this.factoryRegistry.get(itemName)
.getOrElse(throw new Exception("Unable to find factory containing alias " + itemName))
factory.getItem(itemName)
}
def getRegisteredAliases: Set[String] = this.factoryRegistry.keySet
}
I would suggest that this is a clunky pattern in both Java and Scala though. It may be useful from time to time.
Could you give an example of what you want to achieve with this? When do you need to use a different factory based on a runtime value?

Related

jqwik using #ForAll with collection in #Provide-annotated method

Having a hard time figuring out how to utilize #ForAll in jqwik on a #Provide function accepting a collection.
Consider:
// domain model
public class Name {
public final String first;
public final String last;
public Name(String f, String l) {
this.first = f;
this.last = l;
}
}
// jqwik domain context
public class NameDomain extends DomainContextBase {
#Provide
public Arbitrary<Name> arbName() {
return Combinators.combine(
Arbitraries.strings().alpha(),
Arbitraries.strings().alpha()
).as(Name::new);
}
}
// properties test
public class NameProperties {
// obviously a made-up use case, just demonstrating the issue
#Provide
#Domain(NameDomain.class)
public Arbitrary<Set<String>> namesToParse(
#ForAll #Size(min = 1, max = 4) Set<Name> names) {
// ... code here
}
#Property
public void namesAreParsed(#ForAll("namesToParse") Set<String> names) {
// ... code here
}
}
When running this, I end up with:
net.jqwik.api.CannotFindArbitraryException:
Cannot find an Arbitrary for Parameter of type [#net.jqwik.api.ForAll(value="", supplier=net.jqwik.api.ArbitrarySupplier$NONE.class) #net.jqwik.api.constraints.Size(value=0, max=4, min=1) Set] in method [public net.jqwik.api.Arbitrary mypackage.NameProperties.namesToParse(java.util.Set)]
Very similar issues attempting to use #UniqueElements List<Name> instead. What am I missing here?
What you are missing is that the #Domain annotation can only be applied to property methods or their container class. What should therefore work is:
#Property
#Domain(NameDomain.class)
public void namesAreParsed(#ForAll("namesToParse") Set<String> names) {
// ... code here
}
or
#Domain(NameDomain.class)
class NameProperties { ... }
That said, you should be aware that using #ForAll params in a providing method will always use flat mapping over the injected parameters.
Don't use that if you actually want to just map over or combine the injected parameters. In that case your providing method would look something like:
#Provide
public Arbitrary<Set<String>> namesToParse() {
SetArbitrary<Name> names = Arbitraries.defaultFor(Name.class)
.set().ofMinSize(1).ofMaxSize(4);
// Code here just an example of what could be done:
return names.mapEach((Set<Name> ignore, Name n) -> n.first + " " + n.last);
}

Choose which methods to run, with user input

I have a list of methods within my class. And then want to have input string array, where the user can choose which methods they want to run. We are running expensive insurance calculations. And have over say eg 20 methods. Is there a way to conduct this without do an if check on each? maybe with reflection or interface?
#Override
public void ProductTest(ProductData productData, String[] methodNames) {
public void methodA(ProductData productData){...};
public void methodB(ProductData productData){...};
public void methodC(ProductData productData){...};
public void methodD(ProductData productData){...};
public void methodE(ProductData productData){...};
}
I am willing to change the Array into a different ObjectType if needed, to execute properly. Using SpringBoot, has it has a library of utility classes.
Use a Map<String, Consumer<ProductData>>, not separate method handles. Main reason - reflection is slow and dangerous when given user "input"
Use map.get(input).accept(product) to call it.
https://docs.oracle.com/javase/8/docs/api/index.html?java/util/function/Consumer.html
Example
Map<String, Consumer<ProductData>> map = new HashMap<>();
map.put("print_it", System.out::println);
map.put("print_id", data -> System.out.println(data.id));
map.put("id_to_hex", data -> {
int id = data.getId();
System.out.printf("0x%x%n", id);
});
ProductData data = new ProductData(16);
map.get("print_it").accept(data);
map.get("print_id").accept(data);
map.get("id_to_hex").accept(data);
Outputs
ProductData(id=16)
16
0x10
If you are planning on chaining consumers using andThen, you'd be better having an Optional<ProductData>, and using a Function<ProductData, ProductData> with Optional.map()
One way to do it is via reflection. You can iterate over methods in the class object and look for ones to run by name. Here's some example code--this would print out a list of names the user could type in:
myObject.getClass().getDeclaredMethods().each((method)->System.out.println(method.getName()))
And this is how you would call it once the user had made a selection:
productTest.getDeclaredMethods().each((method)->
if(method.getName().equals(userSelectedName))
method.invoke(productTest, productData)
)
The ONLY advantage to this approach is that you don't have to maintain a second structure (Switch, Map, etc...) and add to it every time you add a new method. A personality quirk makes me unwilling to do that (If adding something one place forces you to update a second, you're doing it wrong), but this doesn't bother everyone as much as it bothers me.
This isn't dangerous or anything, if you don't have a method in the class it can't call it, but if you are relying on users "Typing", I'd suggest listing out the options and allowing a numeric selection--or using reflection to build a map like OneCricketeer's.
I've used this pattern to write a testing language and fixture to test set-top TV boxes, it was super simple to parse a group of strings, map some to methods and other to parameters and have a very flexible, easily extensible testing language.
The method object also has a "getAnnotation()" which can be used to allow more flexible matching in the future.
You can use method invocation.
For example, you can have two methods, first one will loop through your methodNames array and call the second method:
public void callPassedMethods(ProductData productData, String[] methodNames) {
for (String m : methodNames) {
callMethod(productData, m)
}
}
And the second method will actually find a method in your class that matches the string passed and invoke it:
public void callMethod(ProductData productData, String methodName) {
try {
ClassName yourObj = new ClassName(); // Class where your methods are
Method method = yourObj.getClass().getDeclaredMethod(methodName, ProductData.class);
method.invoke(yourObj, productData);
} catch(NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
// handle exceptions
}
}
Or, you can always use the good old switch statement:
for (String m : methodNames) {
switch (m) {
case "methodA":
methodA();
break;
case "methodB":
methodB();
break;
// ... continue with as many cases as you need
}
}
If you go with the reflection route, you don't really want to expose your method names to the end users. They might not be end user-friendly, and if they are, there is no reason for users to know this information and there might be methods, which are not supposed to be invoked by users. I would use custom annotations to build more flexible matching.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface UserChoice {
String userFriendlyOption();
int optionNumber();
}
optionNumber will be used for matching the method to invoke, userFriendlyOption is some user friendly text.
Annotate only the methods, supposed to be used by users.
#RequiredArgsConstructor
public class ProductData {
private final double data;
#UserChoice(userFriendlyOption = "see result for option a", optionNumber = 1)
public void methodA() {
System.out.println(data + 1);
}
#UserChoice(userFriendlyOption = "see result for option b", optionNumber = 2)
public void methodB() {
System.out.println(data + 2);
}
#UserChoice(userFriendlyOption = "see result for option c", optionNumber = 3)
public void methodC() {
System.out.println(data);
}
public void methodNotForUser() {
System.out.println("Should not be seen by users");
}
}
Like this methodNotForUser() can't be invoked by end users.
Simplified matcher might look like this.
#RequiredArgsConstructor
public class ProductTester {
private final ProductData data;
private Map<Integer, MethodData> map;
public void showOptions() {
if (this.map == null) {
this.map = new HashMap<>();
for (Method method : this.data.getClass().getMethods()) {
UserChoice userChoice = method.getAnnotation(UserChoice.class);
if (userChoice != null) {
String userRepresentation = userChoice.optionNumber() + " - " + userChoice.userFriendlyOption();
this.map.put(userChoice.optionNumber(), new MethodData(userRepresentation, method));
}
}
}
this.map.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> System.out.println(entry.getValue().getUserRepresentation()));
}
public void showOptionResult(int choice) {
MethodData methodData = this.map.get(choice);
if (methodData == null) {
System.out.println("Invalid choice");
return;
}
System.out.println("Result");
try {
methodData.getMethod().invoke(this.data);
} catch (IllegalAccessException | InvocationTargetException ignore) {
//should not happen
}
}
}
MethodData is simple pojo with the sole purpose to not recalculate user representation.
#RequiredArgsConstructor
#Getter
public class MethodData {
private final String userRepresentation;
private final Method method;
}
Short main to illustrate the idea and play around:
public class Temp {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Write initial value");
double data = scanner.nextDouble();
ProductData myData = new ProductData(data);
ProductTester tester = new ProductTester(myData);
tester.showOptions();
System.out.println("Write option number");
int userChoice = scanner.nextInt();
tester.showOptionResult(userChoice);
}
}

How to organize and test code in functional style in Java

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?

What is the Java pattern to return functions with different signatures based on some condition?

I'm trying to write a Client class which can look up entities from an external data store. The main parameter used to look up entities is a key. The problem is that sometimes a key is just a userId, sometimes it's a combination of userId and productId. So I'd like to enforce the consumer of my Client API to use a key builder specific to an entity. I tried the code below:
import java.util.function.BiFunction;
import java.util.function.Function;
public class Client {
public Function getBuilder(SomeEnum type) {
switch (type) {
case TYPE_X:
BiFunction<String, String, Entity> builder = (userId, productId) -> {
String key = userId + "-" + productId;
// lookup something in external data store based on the key and return the found entity
};
return builder;
case TYPE_Y:
Function<String, Entity> b = appId -> {
String key = userId;
// lookup something in external data store based on the key and return the found entity
};
return b;
}
}
}
The code doesn't compile of course because the return types don't match. I'm wondering if the code can be fixed and if not what is the correct Java pattern to enforce such builders with different signatures.
I would create a KeyBuilder interface as follows, and implement it differently for each type. No enums needed:
public interface KeyBuilder {
String buildKey();
}
// things that use userId & productId:
public class Foo implements KeyBuilder {
// ...
public String buildKey() { return userId + "-" + productId; }
}
// things that use appId {
public class Bar implements KeyBuilder {
// ...
public String buildKey() { return appId; }
}
Then, your code becomes cleaner and is still easy to test
// before: have to build explicitly
lookupSomethingExternal(foo.getUserId() + "-" + foo.getProductId());
lookupSomethingExternal(bar.getAppId());
// after: lookupSomethingInternal expects something implementing KeyBuilder
lookupSomethingExternal(foo);
lookupSomethingExternal(bar);
// after: can mock for unit-tests
lookupSomethingExternal(() -> "testKey");

Use the command line to make new objects

In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}

Categories

Resources