factory like pattern with spring bean without switch case - java

My goal is to return a method depending on a enum. Currently, I have created a factory but it's using a switch case that I dislike. The code is working fine but I want to use a better pattern and replace the current switch case. How would you design this without any switch case or if else (instance of)...
I tried also to implement a Stategy pattern in enum. But autowiring beans is not possible.
See below my current piece of code.
public enum Car {
AUDI, FORD;
}
public class SuperCar{
private Car car;
}
public class Audi extends SuperCar{
// some other properties
}
public class Ford extends SuperCar{
// some other properties
}
#Service
public class AudiService{
public void save(Audi audi){
// some code
}
}
#Service
public class FordService{
public void save(Ford ford){
// some code
}
}
#Service
public class CarFactory{
private FordService fordService;
private AudiService audiService;
public CarFactory(FordService fordService, AudiService audiService) {
this.fordService = fordService;
this.audiService = AudiService;
}
public void saveCar(SuperCar superCar){
switch(superCar.getCar()):
case AUDI:
return audiService.save((Audi)superCar));
case FORD:
return fordService.save((Ford)superCar));
default:
return null;
}
}
Thank you for any help.

In case of just replacing the switch, I would always prefer a more declarative approach by using a map, since it seams easier to maintain and to read:
private Map<Car, CarService> services;
public CarFactory(FordService fordService, AudiService audiService) {
this.services = Map.of(Car.FORD, fordService, Car.AUDI, audiService);
}
public void saveCar(SuperCar superCar) {
CarService service = services.get(superCar.getCar());
if (service != null) service.save(..);
}
With the generic interface:
private interface CarService<T extends SuperCar> {
void save(T car);
}
Anyway, I would rethink your object-model to let a super-car save itself (as others already suggested).

I'm sorry that I can't comment. Here the type of the car determines the car service. I'm not sure If the strategy patterns fits in here. I would use strategy pattern when there is a varying service behavior for the same car. Eg: In summer I want to use XService and in Winter I want to use YService for AUDI. I see two ways to implement this.
Inject the service during the creation of car object. With this implementation the car is tightly coupled with service. I don't recommend this, unless you have a strong reason to not follow point 2.
Use if/else or branching to determine the type of car and call the required service.

Related

how to rewrite this code to avoid switches/casting

Simplified example to give you an idea, hope it's be clear.
I've already added inheritance for Service class to avoid switches I'm having now
class Config {}
class ConfigA extends Config {}
class ConfigB extends Config {}
// service class - different implementation for configA and ConfigB
// normally it would look like
class ServiceA {
public String run(ConfigA configA) {}
}
thus next then I need sth like
class ServiceRunner {
public String run(Config config) {
// if or switch doesn't matter now
if (config instanceof ConfigA) {
return serviceA.run((ConfigA)config);
}
}
}
// main
Config config = configFactory.create(...) // returns ConfigA or ConfigB
String result = serviceRunner.run(config);
Is there a better way to code it I mean without casting?
The only solution I can see is:
interface Service { String run(); }
#RequestScope
class ServiceA implements Service {
private ConfigA config;
public ServiceA(ConfigA configA) {this.configA = configA}
public String run() {
...
}
}
but I'm not convinced it's a good idea to implement service beans as state beans and I'm using CDI (quarkus actually) for DI which it seems doesn't support assisted injection via constructor
Why don't you hide the detail about which Config a given Service handles inside the Service itself? By doing so you could have something like the following:
interface Service {
boolean handlesConfig(Config config)
String run(Config config);
}
class ServiceRunner {
private List<Service> services;
public String run(Config config) {
for (service : services) {
if (service.handles(config)) {
return service.run(config);
}
}
}
}
Seems like it's a case for Bridge pattern. You have parallel hierarchies of service and config. So if tomorrow there is a ServiceC, there would supposedly be a ConfigC. There might be an abstraction which is common in both service and config. Try to find it and abstract it out. Then service would be using that abstraction. And ConfigA, ConfigB would be impls of that abstraction.
Or perhaps, as the replier above mentioned, service should be programmed to the abstract config instead of impls.
Does the Configs have different types of interfaces that can't be extracted into a common interface? In that case, it is violating the Liskov's substitution principle, which requires that all subclasses should be interchangeable. e.g. the hierarchy of Shape <- Rectangle <- Square is wrong, because square is not a type of rectangle (programmatically, of course) - because Rectangle has 2 dimensions, namely length and breadth, while square has one dimension of length only. Making this hierarchy would break the abstraction. Similarly, it might be your case that the hierarchy of Config may not be a hierarchy at all.

Does strategy always needs to be passed from the client code in Strategy Pattern?

I have below piece of code:
public interface SearchAlgo { public Items search(); }
public class FirstSearchAlgo implements SearchAlgo { public Items search() {...} }
public class SecondSearchAlgo implements SearchAlgo { public Items search() {...} }
I also have a factory to create instances of above concrete classes based on client's input. Below SearchAlgoFactory code is just for the context.
public class SearchAlgoFactory {
...
public SearchAlgo getSearchInstance(String arg) {
if (arg == "First") return new FirstSearchAlgo();
if (arg == "Second") return new SecondSearchAlgo();
}
}
Now, I have a class that takes input from client, get the Algo from Factory and executes it.
public class Manager{
public Items execute(String arg) {
SearchAlgo algo = SearchAlgoFactory.getSearchInstance(arg);
return algo.search();
}
}
Question:
I feel that I am using both Factory and Strategy pattern but I am not sure 'cause whatever examples I have seen they all have a Context class to execute the strategy and client provides the strategy which they want to use. So, is this a correct implementation of Strategy?
If it comes to implementing design patterns, it is much more important to understand what they do than to conform to some gold standard reference implementation. And it looks like you understand the strategy pattern.
The important thing about strategies is that the implementation is external to some client code (usually called the context) and that it can be changed at runtime. This can be done by letting the user provide the strategy object directly. However, introducing another level of indirection through your factory is just as viable. Your Manager class acts as the context you see in most UML diagrams.
So, yes. In my opinion, your code implements the strategy pattern.

Is it safe to use String as a return type of a bean in spring?

#Configuration
public class Product {
#Bean("xyz")
public String getMethod() {
return "abc";
}
}
#Component
public class Test {
String b;
Test(String xyz) {
this.b = xyz;
}
}
Is this any harm with this approach? I am trying to make change in the existing code where I am replacing the #Value with the getter as the method parameter. As I don't want to change the structure of the existing code I am trying to inject the method as bean as a replacement to #Value.
I suggest you to keep the #Value annotation instead of the whole #Bean configurations.
Why?
What if the getMethod()'s returned value needs to be changed very often? Everytime when you're changing something in the Product class, during build time it needs to be recompiled. What happens if the project is getting bigger and you're using this approach? It leads to longer build time and the more important thing is that this solution is not intuitive and it's hard to keep it clean. Don't think about complex solutions only to make the code look fancy. When you need to inject String values, the easiest approach is to create properties files (which won't get recompiled) and use the #Value annotation.
Now, if you want to add new methods without changing the structure of the existing code there are some patterns which you can apply like decorator pattern.
The main idea is simple: you're creating a decorator class which has an object of the type you need.
The easiest example (which you'll find everywhere on the internet) is the classic Shape example:
public interface Shape {
String someMethod();
}
#Component
public class CustomShape implements Shape { //implement the method here }
And here is the decorator:
public interface ShapeDecorator {
String someMethodExtended();
void someExtraMethod();
}
#Component
public class CustomShapeDecorator implements ShapeDecorator{
#Autowired
// #Qualifier - optional (only if you have more Shape implementations)
private Shape shape;
// now you can either:
// 1. provide new methods
#Override
public void someExtraMethod(){
System.out.println("Hello world!");
}
// 2. or you can EXTEND the Shape's "someMethod()" implementation
#Override
public String someMethodExtended(){
String oldString = this.shape.someMethod();
return oldString + " EXTENDED";
}
}

Java what design pattern should I use for object instantiation if I have different constructor but same interface?

I'm learning about the design patterns and I encountered a problem which I cant resolve. I'm writing a client/server script. The administrator client send a task with its task data in json format, and the server should instantiate an object accordingly to the recieved task type, and fill its constructor with correct classes. As you can see bellow there are two example class.
public class StartProcessing implements ITask{
private final IProcessor dataProcessor;
public StartProcessing(IProcessor dataProcessor){
this.dataProcessor = dataProcessor;
}
#Override
public void ProcessTask() {
this.dataProcessor.StartProcess();
}
}
public class StartQueueFiller implements ITask{
private IQueueFiller queueFiller;
public StartQueueFiller(IQueueFiller queueFiller){
this.queueFiller = queueFiller;
}
#Override
public void ProcessTask() {
this.queueFiller.Start();
}
}
interface ITask {
public void ProcessTask();
}
I've tried something like this, but I'll have like 50 different process and hundreds of tasks, so the constructor will be unmanageable, and I think the factory pattern is not so good in this case, and probably I just miss the point of the pattern. So how you would solve this problem? What should I use instead of the factory pattern?
public class TaskFactory(){
private final IProcessor processor;
private final IQueueFiller queuefiller;
public TaskFactory(IProcessor processor, IQueueFiller queuefiller){
this.processor = processor;
this.queuefiller = queuefiller;
}
public ITask Create(String task){
switch(task){
case "startprocessor":
return new StartProcessing(this.processor);
case "startqueuefiller":
return new StartQueueFiller(this.queuefiller);
}
}
}
I would just use the Abstract Factory pattern:
public interface TaskFactory {
Task create();
}
Then we can store a bunch of factories in a data structure of some kind, e.g.:
private final Map<String, TaskFactory> factoriesMap = new HashMap<>();
void registerFactory(String identifier, TaskFactory factory) {
factoriesMap.put(identifier, factory);
}
public Task create(String identifier) {
return factoriesMap.get(identifier).create();
}
Then we can register different kinds of factories using a lambda or something:
Processor processor = ...;
registerFactory("startprocessor", () -> new StartProcessingTask(processor));
etc.
At some point you're going to realize that your "factory map" is basically a kind of Service Locator, in which case you either need to double-down on that, or find an alternative solution. I tend to prefer Dependency Injection as an approach here. Depending on your DI environment, you might make all your TaskFactory instances injectable using qualifiers. You can either bind lazy providers of actual task objects, or bind a factory-like object (e.g. "assisted inject").

How to delegate to services by class type?

I have different class types, and depending on some conditions, I want to delegate to the appropriate service that can handle those class types.
Example:
I have several classes as follows.
class Student;
class Prof;
...
For each class there is a service, implementing:
interface IPersonService {
void run();
}
And I have a mode that is found by some conditions:
enum PersonType {
STUDENT, PROF;
}
When I delegate:
#Autowired
private StudentService studentService;
#Autowired
private ProfService profService;
//#param mode assume known
public void delegate(PersonType mode) {
//assume there are several of those switch statements in my business code
switch (mode) {
case STUDENT: studentService.run(); break;
case PROF: profService.run(); break;
default: break;
}
}
Problem: When introducing additional classes, I have to both modify the PersonType and add an additional enum (which is no problem), but I also have to extend any switch statement and add calls to additional delegation services. Also I have to explicit autowire those services to the switch delegator.
Question: how could I optimize this code, to just implementing new Services for any additional class, and not having to touch any of the switch statements?
Add a method to IPersonService so that the implementation of the method can tell the program what type of persons it handles:
interface IPersonService {
PersonType supportedPersonType();
void run();
}
In the service that does the delegation, inject a List<IPersonService>, which Spring will fill with all the implementations of IPersonService that it can find. Then implement the delegate method to look through the list to find the first IPersonService that can handle the specific type.
#Autowired
private List<IPersonService> personServices;
public void delegate(PersonType mode) {
for (IPersonService personService : personServices) {
if (personService.supportedPersonType().equals(mode)) {
personService.run();
break;
}
}
}
This way, you can add new implementations of IPersonService without having to change the service that does the delegation.
To avoid having to go through the loop each time delegate is called, you could build a Map beforehand so that the right IPersonService can be looked up quickly:
class DelegatingService {
#Autowired
private List<IPersonService> personServices;
private Map<PersonType, IPersonService> personServiceMap;
#PostConstruct
public void init() {
personServiceMap = new HashMap<>();
for (IPersonService personService : personServices) {
personServiceMap.put(personService.supportedPersonType(), personService);
}
}
public void delegate(PersonType mode) {
personServiceMap.get(mode).run();
}
}
(Error handling omitted for simplicity).
In my application, we solved similar problem, by putting services into a map. Consider Map<PersonType,IPersonService> serviceMap defined as bean and injected into your class.
Then delegate method simple do
public void delegate(PersonType mode) {
IPersonService service = serviceMap.get(mode);
if (service!=null){
service.run();
}else{
//do something if service is null
}
}
You can store the service bean name (or class type) in the enum, and fetch the beans from the application context using getBean by name (or by class type respectively).
Also, all the services will need to implement a interface which has the run method.
interface ModeService {
void run();
}
enum PersonType {
STUDENT("studentService"), PROF("profService");
private String serviceBean;
public PersonType(String serviceBean) {
this.serviceBean = serviceBean);
}
public String getServiceBean() {
return serviceBean;
}
}
in delegate then the following can be used. ((ModeService)applicationContext.getBean(mode.getServiceBean()).run()
This way only the enum needs to be updated with the service type that is to be used, and no change to delegate method is required.

Categories

Resources