I have a client like with a constructor which is quite lengthy in terms of the argument list , e.g,
Class Client {
private ServiceA _serviceA;
private ServiceB _serviceB;
....
private ServiceE _serviceE;
public Client(ServiceA serviceA, ServiceB serviceB,...ServiceE service E) { ... }
public doTask1(TypeA typeA) { //only serviceA, serviceB service being used... }
public doTask2(TypeB typeB) { //only serviceD, serviceE being used ... }
}
I want to use a service facade here to prune the constructor argument list. However, I am pretty confused as the core responsibility of the facade implementation. So I have written down a facade with the services as the class variables and their getters , as below:
Class Facade {
private ServiceA _serviceA;
private ServiceB _serviceB;
....
private ServiceE _serviceE;
getters () ...
}
Is this correct way to abstract facade in this case. If not , what would have been the proper way to refactor the Client class?
Facedes has a completely different intent: they are created to encapsulate and hide the underlying structure and behaviour of classes. Take an example of a car. It's made of many components: on-board computer, fuel pump, engine etc. If you want to start it, just press the start button:
class FuelPump {
private boolean pumpTurnedOn;
public FuelPump() {
pumpTunrnedOn=false;
}
public boolean isPumpTunredOn() {
return pumpTurnedOn;
}
public void setPumpTurnedOn (boolean newState) {
pumpTurndeOn=newState;
if (newState) {
System.out.println ("fuel pump now is on");
} else {
System.out.println ("fuel pump now is turned off");
}
}
}
class Engine {
private boolean engineStarted;
public Engine() {
engineStarted=false;
}
public boolean isEngineStarted() {
return engineStarted;
}
public void setEngineStarted (boolean newState) {
engineStarted=newState;
if (newState) {
System.out.println("engine now is on");
} else {
System.out.println("engine now is turned off");
}
}
}
// this is the Car facade:
class Car {
private FuelPump fuelPump;
private Engine engine;
// + other components of Car
public Car () {
fuelPump = new FuelPump();
engine = new Engine();
}
public void startCar() {
fuelPump.setPumpTurnedOn(true);
engine.setEngineStarted(true);
// + other methods of start procedures with other components
System.out.println("Your car has been startded");
}
public void stopCar() {
engine.setEngineStarted(false);
fuelPump.setPumpTurnedOn(false);
// + other methods on other components for shutting down car
}
}
The client code snippet:
Car car=new Car();
car.startCar();
// later on
car.stopCar();
As you may see the client doesn't know anything about the underlying components to start the car. It has only to use the startCar() method, and the Car facade will do the rest. Facade is a structural pattern.
If you have many constructor arguments and want to reduece them use one of the creational patterns. In case you have compulsory and non compulsory fields I suggest using the builder pattern.
For example your compulsory constructor arguments are Service_A and Service_B and Service_C to Service_E are not required.
Then your ClientBuilder class should like be this:
class ClientBuilder{
private static Service_A serviceA; // required
private static Service_B serviceB; // required
private static Service_C serviceC;
private static Service_D serviceD;
private static Service_E serviceE;
// since this builder is singleton
private static ClientBuilder builderInstance = new ClientBuilder();
private ClientBuilder () {};
public static ClientBuilder getBuilderInstance (Service_A service_A, Service_B service_B){
serviceA = service_A;
serviceB = service_B;
serviceC = null;
serviceD = null;
serviceE = null;
return builderInstance;
}
public static ClientBuilder addServiceC (Service_C service_C) {
serviceC = service_C;
return builderInstance;
}
public static ClientBuilder addServiceD (Service_D service_D) {
serviceC = service_D;
return builderInstance;
}
public static ClientBuilder addServiceE (Service_E service_E) {
serviceE = service_E;
return builderInstance;
}
public static Client build(){
return new Client (serviceA, ServiceB, ServiceC, ServiceD, ServiceE);
}
In this case you can instantinate your Client class only with the mandatory arguments. The best thing is the not required arguments' order are interchangeable:
Client aClient = ClientBuilder.getBuilderInstance(aServiceA, aServiceB)
.addServiceE(aServiceE)
.addServiceC(aServiceC)
.build();
Now aClient has been created with services A,B,C,E and serviceD remains null. Later you can set it by appropriate setter. The getters and setters must be in your Client class.
To put it in a nutshell, with builder class you can reduce the number of constructor arguments only for the mandatory and set up optional fields later with setters.
You can read more details in the Gang of Four book or if you are a serious Java fun I suggest Head First's Design Patterns book.
Hope I could help you, bye!
Related
According to the SOLID principle open and close principle says class is open for extension and closed for modification.
So I am allowed to add new logic based on new if-else conditions?
If I will not use conditionals so how will I identify based on which condition which action has to be applied
public interface TemplateClassification {
QuesObj processTemplate(RawPart rawPart);
}
public class Template1 implements TemplateClassification{
#Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 1"+rawPart.getHead(),"Hi I am footer 1"+rawPart.getFoot());
}
}
public class Template2 implements TemplateClassification{
#Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 2"+rawPart.getHead(),"Hi I am footer "+rawPart.getFoot());
}
}
public class TemplateInfo {
private TemplateClassification templateClassification;
public TemplateClassification getTemplateClassification() {
return templateClassification;
}
public void setTemplateClassification(TemplateClassification templateClassification) {
this.templateClassification = templateClassification;
}
}
public class TemplateProduct {
public QuesObj calculateTemplate(TemplateInfo templateInfo,RawPart rawPart){
QuesObj ques = templateInfo.getTemplateClassification().processTemplate(rawPart);
return ques;
}
}
#RestController
class Pg {
#Autowired
TemplateInfo templateInfo;
#Autowired
TemplateProduct templateProduct;
public doProcessing(RawPart rawPart){
QuesObj ques = null;
if(rawPart.getId() == 1){
Template1 temp = new Template1();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(rawPart.getId() == 2){
Template2 temp = new Template2();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(tempId == 3){
// coming soon
}
}
}
How can i eliminte the if else condition so that it can follow open-close principle
To implement the "O" in SOLID, you can follow the below, which includes the "S" as well.
We are going to use polymorphism and inheritance.
Step 1 :
Create an interface that will sit in front of the classes that will be responsible in creating the QuesObj. We are going to need this, because down the line the code could receive a creator (child class) when id is 1,2 or 3.
It is important to note that QuesObj was identified because that is being returned on your original if statements and this is the reason we are allowed to continue with this approach.
public interface QuesObjCreator {
QuesObj calculate(RawPart rawPart);
}
Step 2:
Create individual class that creates the QuesObj in different ways in The only role of that class is to create the object.
public class QuesObjCreatorFor1 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
#Override
public QuesObj calculate(RawPart rawPart) {
Template1 temp = new Template1();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
public class QuesObjCreatorFor2 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
#Override
public QuesObj calculate(RawPart rawPart) {
Template2 temp = new Template2();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
Step 3:
Create a factory to return a QuesObjCreator. The factory will be returned to your main code/service.
public class QuesObjectCreatorFactory {
private static final Map<Integer,QuesObjCreator> quesObjCreatorMap = new HashMap<>();
public QuesObjectCreatorFactory() {
quesObjCreatorMap.put(1,new QuesObjCreatorFor1());
quesObjCreatorMap.put(2,new QuesObjCreatorFor2());
}
public static QuesObjCreator getQuesObjCreator(final int number) {
final QuesObjCreator quesObjCreator = quesObjCreatorMap.get(number);
if(quesObjCreator == null) {
throw new IllegalArgumentException("QuesObj for "+number+" does not exist");
}
return quesObjCreator;
}
}
Step 4:
Use Factory to create the QuesObj
public class Pg {
public void doProcessing(RawPart rawPart){
final QuesObjCreator quesObjCreator = QuesObjectCreatorFactory.getQuesObjCreator(rawPart.getId());
QuesObj ques = quesObjCreator.calculate(rawPart);
}
}
Collectively we achieved the Single responsibility across all classes and are decoupled.
It is easy to maintain cause now you can add more options to create QuesObj and none of the code would change, thus achieving open for extensibility/closed for modification.
It all boils down to the Factory and Map that has the creators. The map has to be populated with all the creator instances. With Spring this can be very easy, as Spring can scan your project, find beans of a specific type, give you a List and then you can convert it to a map.
Your case has nothing to do with SOLID. According to open-closed principle, you cannot allow modification to your class IN RUNTIME that can break its behavior.
In your case I suggest the following:
Add getId() method to your TemplateClassification interface.
Make each TemplateClassification implementation a bean
Add bean that will form the map of templates for you
#Bean
public Map<Integer, TemplateClassification> templates(List<TemplateClassification> templates) {
return algorithms.stream()
.collect(Collectors.toMap(TemplateClassification::getId, Function.identity()));
}
Autowire Map<Integter, TemplateClassification> templates to your controller and find the required template by id.
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/
Let's say if I have a test that uses builders to construct objects. The problem is that the builder() method in the builder class is static.
Generally, mocking a static method is already an indicator of bad design. However, in the case of builders, the builder() methods are always static. What's the best approach to unit testing methods using builders()? Should the builders be refactored into a separate class to facilitate mocking?
class Service {
private SqsClient sqsClient;
private String sqsQueueUrl;
public Service(String sqsQueueUrl) {
this.sqsClient = SqsClient.builder().build();
this.sqsQueueUrl = sqsQueueUrl;
}
public SqsClient getClient() {
return this.client;
}
public SqsClient setClient(SqsClient client) {
this.client = client;
}
public String getSqsQueueUrl() {
return this.sqsQueueUrl;
}
public void setSqsQueueUrl(String sqsQueueUrl) {
this.sqsQueueUrl = sqsQueueUrl;
}
public void onEvent(Activity activity) {
// How to mock builders in unit test?
DeleteMessageRequest deleteRequest = DeleteMessageRequest.builder().queueUrl(this.sqsQueueUrl).receiptHandle(activity.getReceiptHandle()).build();
DeleteMessageResponse deleteMessageResponse = this.sqsClient.deleteMessage(deleteRequest);
}
}
class ServiceTest {
#Test
public void testEvent() {
String sqsQueueUrl = "http://127.0.0.1";
String receiptHandle = "asdasd";
SqsClient sqsClient = EasyMock.mock(SqsClient.class);
Service service = EasyMock.mock(Service.class);
// EasyMock expect and replay here.
service.setClient(sqsClient);
service.setSqsQueueUrl(sqsQueueUrl);
Activity activity1 = new Activity();
activity.setReceiptHandle(receiptHandle);
service.onEvent(activity);
}
}
I have a small problem which I can't figure out to save my life.
Basically I need to register classes anytime dynamically using guice and then loop through them all.
Lets say this is my class to register Strategies but these strategies can be added anytime through the application running.
// Strategy registration may happen anytime, this is just an example
strategyManager.register(ExampleStrategy1.class);
strategyManager.register(ExampleStrategy2.class);
StrategyImpl class
public class StrategyImpl implements Strategy {
#Override
public void register(Class<? extends StrategyDispatcher> strat) {
//Add this class into provider or create an instance for it and add it into guice but how?
}
#Override
public void dispatchStrategy() {
//Find all strategies and execute them
}
}
I've tried using a Provider but have no idea how i'd add the registered class into the provider and retrieve them all?
#Override
protected void configure() {
bind(Strategy.class).toProvider(StrategyProvider.class);
}
My provider class always gets the same instance
public class StrategyProvider implements Provider<StrategyDispatcher> {
public LogManager get() {
return new StrategyDispatcherImpl();
}
}
The strategies that I add extend the StrategyDispatcherImpl class so i could cast them?
I need to add multiple binds to a same instance but it needs to be done dynamically and not using the bind method in configure but another way then be able to find all these strategies and execute them.
If you truly need it to happen at "any time" during the application life cycle then Guice then I think you will need some sort of Guice-aware Factory. I.e.
public class TestStuff {
#Test
public void testDynamicCreation() {
Injector injector = Guice.createInjector();
StrategyManager manager = injector.getInstance(StrategyManager.class);
Hello hello = injector.getInstance(Hello.class);
manager.doStuff();
assertThat(hello.helloCalled, is(false));
manager.register(Hello.class); // DYNAMIC!!
manager.doStuff();
assertThat(hello.helloCalled, is(true));
}
}
interface Strategy {
void doStuff();
}
#Singleton
class Hello implements Strategy {
boolean helloCalled = false;
public void doStuff() {
helloCalled = true;
}
}
class StrategyManager {
private final Collection<Strategy> strategies = new ArrayList<>();
private final StrategyFactory factory;
#Inject
StrategyManager(StrategyFactory factory) {
this.factory = factory;
}
public void register(Class<? extends Strategy> strat) {
strategies.add(factory.create(strat));
}
public void doStuff() {
for (Strategy s : strategies) {
s.doStuff();
}
}
}
class StrategyFactory {
private final Injector injector;
#Inject
StrategyFactory(Injector injector) {
this.injector = injector;
}
public Strategy create(Class<? extends Strategy> clazz) {
return injector.getInstance(clazz);
}
}
If it is not "dynamic" after the initialization phase then you are after the "multibinder" I think.
I want to use Guice and GuiceBerry to inject a non-static legacy service into a factory class. I then want to inject that factory into my Parameterized JUnit test.
However, the issue is JUnit requires that the #Parameters method be static.
Example factory:
#Singleton
public class Ratings {
#Inject
private RatingService ratingService;
public Rating classicRating() {
return ratingService.getRatingById(1002)
}
// More rating factory methods
}
Example test usage:
#RunWith(Parameterized.class)
public class StaticInjectParamsTest {
#Rule
public GuiceBerryRule guiceBerryRule = new GuiceBerryRule(ExtendedTestMod.class)
#Inject
private static Ratings ratings;
#Parameter
public Rating rating;
#Parameters
public static Collection<Rating[]> ratingsParameters() {
return Arrays.asList(new Rating[][]{
{ratings.classicRating()}
// All the other ratings
});
}
#Test
public void shouldWork() {
//Use the rating in a test
}
}
I've tried requesting static injection for the factory method but the Parameters method gets called before the GuiceBerry #Rule. I've also considered using just the rating's Id as the parameters but I want to find a reusable solution. Maybe my approach is flawed?
Unfortunately, JUnit needs to be able to enumerate all of the tests before running any tests, so the parameters method must be called before rules.
You could define an enum for the type of rating:
#RunWith(Parameterized.class)
public class StaticInjectParamsTest {
#Rule
public GuiceBerryRule guiceBerryRule
= new GuiceBerryRule(ExtendedTestMod.class);
#Inject
private Ratings ratings;
#Parameter
public RatingType ratingType;
#Parameters
public static Collection<RatingType> types() {
return Arrays.asList(RatingType.values());
}
#Test
public void shouldWork() {
Rating rating = ratings.get(ratingType);
// Use the rating in a test
}
}
Edit: Code for enum:
public enum RatingType {
CLASSIC(1002),
COMPLEX(1020);
private final int ratingId;
private RatingType(int ratingId) {
this.ratingId = ratingId;
}
// option 1: keep rating ID private by having a method like this
public get(RatingService ratingService) {
return ratingService.getRatingById(ratingId);
}
// option 2: have a package-scope accessor
int getRatingId() {
return ratingId;
}
}
Edit: if you go with option 2 you would then add a new method to get a Rating from a RatingType which would delegate to the service passing ratingId:
#Singleton
public class Ratings {
#Inject
private RatingService ratingService;
public Rating getRating(RatingType ratingType) {
return ratingService.getRatingById(
ratingType.getRatingId());
}
// More rating factory methods
}
If you don't want RatingType to be in your public API, you can define it in your test, and have a method in the enum named getRating()
public enum RatingType {
CLASSIC {
#Override public Rating getRating(Ratings ratings) {
return ratings.getClassicRating();
}
},
COMPLEX {
#Override public Rating getRating(Ratings ratings) {
return ratings.getComplexRating();
}
};
public abstract Rating getRating(Ratings ratings);
}
You could also create a value type instead of an enum.
This assumes you can write tests that should pass for all Rating instances.
If you have some common tests but some rating-specific tests, I would make an abstract base class that contains common tests, and an abstract createRating() method, and subclass it for every rating type.
My solution was to add a RatingId class that wraps an integer and create a factory RatingIds that I could then return static and use as parameters. I overloaded the getRatingById method in my RatingService interface to accept the new RatingId type, and then inject the rating service into my test and use it directly.
Added factory:
public class RatingIds {
public static RatingId classic() {
return new RatingId(1002);
}
// Many more
}
Test:
#RunWith(Parameterized.class)
public class StaticInjectParamsTest {
#Rule
public GuiceBerryRule guiceBerryRule = new GuiceBerryRule(ExtendedTestMod.class)
#Inject
private RatingService ratingService
#Parameter
public RatingId ratingId;
#Parameters
public static Collection<RatingId[]> ratingsParameters() {
return Arrays.asList(new RatingId[][]{
{RatingIds.classic()}
// All the other ratings
});
}
#Test
public void shouldWork() {
Rating rating = ratingService.getRatingById(ratingId.getValue())
//Use the rating in a test
}
}
In cases as yours, where the total number of generated parameter sets is known in advance, but building the parameters itself requires some context (e.g. autowired service instance with Spring) you can go the functional approach (with junit5 & parameterized)
Obviously that does not work, if the createParameter function itself depends on such contex:-/
class MyTestClass {
// may be autowired, cannot be static but is required in parameter generation
SomeInstance instance;
private interface SomeParamBuilder { SomeParam build(SomeInstance i);}
private static Stream<Arguments> createParamterFactories() {
return Stream.of(
Arguments.of((SomeParamBuilder)(i)->
{
return new SomeParam(i);
})
);
}
// does not work, because SomeParam needs SomeInstance for construction
// which is not available in static context of createParameters.
//#ParameterizedTest(name = "[{index}] {0}")
//#MethodSource("createParameters")
//void myTest(SomeParam param) {
//}
#ParameterizedTest(name = "[{index}] {0}")
#MethodSource("createParamterFactories")
void myTest(SomeParamBuilder builder) {
SomeParam param = builder.build(instance);
// rest of your test code can use param.
}
}
maven dep:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
I did not get guiceberry to run (ancient dependencies), but using JUnitParamters and plain guice, this is rather simple:
#RunWith(JUnitParamsRunner.class)
public class GuiceJunitParamsTest {
public static class SquareService {
public int calculate(int num) {
return num * num;
}
}
#Inject
private SquareService squareService;
#Before
public void setUp() {
Guice.createInjector().injectMembers(this);
}
#Test
#Parameters({ "1,1", "2,4", "5,25" })
public void calculateSquares(int num, int result) throws Exception {
assertThat(squareService.calculate(num), is(result));
}
}
If you check the JUnitParams website, you will find a lot of other ways to define the parameters list. It is really easy to do this with the injecte service.