Status:
Answers of Fendy and Glen Best are equally acceptable and honored by me but since one can be accepted and bounty be given, I choose Fendy's answer.
Scenario:
If I have some code that has to be reused many times in many classes (rarely with minor parameter changes which is obvious) and concurrent threads, Which approach to go for?
The code that has to be reused can be any sane thing (with appropriate care of static and non-static context in mind and method making techniques). It can be an algorithm, A DB method doing connect,operate,close. Anything.
Make some class like MyMethods.class
and put all those methods in it.
1.a. Make methods static
and call (by all classes and concurrent threads) directly as MyMethods.someMethod();
1.b. Make methods non-static
and at the time to call them, instantiate
the whole class by MyMethods mm = MyMethods(); mm.someMethod();
Use Strategy pattern stated at https://en.wikipedia.org/wiki/Strategy_pattern (code attached here with).
Use dependency injection stated at https://en.wikipedia.org/wiki/Dependency_injection#Java
Problems:
Some people would say Unit test http://en.wikipedia.org/wiki/Unit_testing wont be possible with this approach, will make trouble in swaping out latter. if you want to test your class and use a mock version of the dependency
1.a. Will there be any problems with concurrent calls or multiple classes? specially in JDBC static methods
for just an example?
1.b. I think it would make too much memory load as a whole class would be instanticated
many times just to call one or two methods
Thats way over my head, do explain that and or any advantages/disadvantages
I do Not want to use a framework in context to this question.. Thats way over my head, do explain that and or any advantages/disadvantages
Awaiting any other strategies or recommendations, if any.
Request:
Please only answer if you are experienced and know the implications deeply and can comprehensively, with your answer, help me and the community as a whole!
Code:
/** The classes that implement a concrete strategy should implement this.
* The Context class uses this to call the concrete strategy. */
interface Strategy {
int execute(int a, int b);
}
/** Implements the algorithm using the strategy interface */
class Add implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Add's execute()");
return a + b; // Do an addition with a and b
}
}
class Subtract implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Subtract's execute()");
return a - b; // Do a subtraction with a and b
}
}
class Multiply implements Strategy {
public int execute(int a, int b) {
System.out.println("Called Multiply's execute()");
return a * b; // Do a multiplication with a and b
}
}
// Configured with a ConcreteStrategy object and maintains
// a reference to a Strategy object
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int a, int b) {
return this.strategy.execute(a, b);
}
}
/** Tests the pattern */
class StrategyExample {
public static void main(String[] args) {
Context context;
// Three contexts following different strategies
context = new Context(new Add());
int resultA = context.executeStrategy(3,4);
context = new Context(new Subtract());
int resultB = context.executeStrategy(3,4);
context = new Context(new Multiply());
int resultC = context.executeStrategy(3,4);
System.out.println("Result A : " + resultA );
System.out.println("Result B : " + resultB );
System.out.println("Result C : " + resultC );
}
}
Your question actually has two meanings.
that has to be reused many times in many classes
It can be a context of design pattern (reusable component) or memory cost (class instantiation). Talking from two different perspective:
This section actually only cover 2 kind of instantiation.
First is static (or DI instantiation in composition root)
Non-static
In short, static will cost high if the class is many, and non-static will cost high if the request is high (inside for loop, for example). But it should not make your application heavy. Most operation in java / csharp are creates objects though.
1 - mega monolithic code (one god class able to do almost everything)
Advantages:
Disadvantages:
1a / static class / singleton pattern
Advantages:
Disadvantages:
Some point about static class: see this question
2 strategy pattern
Actually this has the same design with 3 or composition over inheritance
.
3 dependency injection
Advantages:
Must be stateless
. It is easier to debug and unit test if the class is statelessThe disadvantage:
I think states plays important rules in your application design. Usually developers try to avoid having states in business logic code, such as:
// get data
if(request.IsDraft){
// step 1
// step 2
}
else{
// step 1
// step 3
}
Developers tend to put the logic in other stateless
class, or at least methods such as:
// get data
if(request.IsDraft){
draftRequestHandler.Modify(request);
}
else{
publishedRequestHandler.Modify(request);
}
It will provide in better readability, and easier for modification and unit tests. There is one design pattern state pattern or hierarchial state machine pattern
too, especially to handle some cases like this.
IMHO, this principle is has the most benefit if followed. The advantages are:
This design does not guarantee your code free of bugs. In cons of costing time at design phase and layering effort, it has the benefit of:
Service Locator Anti Pattern
Using Decorator for cross-cutting concern
My 2 cents:
The benefit of using interface (also apply for composition ofer inheritance)
Doing top down design / DI design
Those designs and strategies are not the key which will determine your application structure. It still the architect who will determine it. I prefer to follow some principles such as SOLID, KISS and GRASP, rather than deciding what is the best structure. It is said that Dependency Injection follow the most of those principles, but too much abstraction and incorrect components design will resulting the same with the misuse of singleton pattern.
1.a. Make methods static and call (by all classes and concurrent threads) directly as MyMethods.someMethod();
1.b. Make methods non-static and at the time to call them, instantiate the whole class by MyMethods mm = MyMethods(); mm.someMethod();
The choice between these two depends on the functionality of MyMethods.class
. If MyMethods
is supposed to be stateless then it's a good approach to go with static
methods. Otherwise, if one method call depends on another and MyMethods
have states (i.e. non-final fields) then use the second option.
Use Strategy pattern stated at https://en.wikipedia.org/wiki/Strategy_pattern (code attached here with).
Use this pattern if MyMethods
are to be extended with different classes for different purposes and if you select which code to run depending on your context. As the wiki says, if you the algorithm to be used is not known before the runtime (depends on some conditions) this is the way to go. According to your specification of MyMethods
you do not have such problems.
Use dependency injection stated at https://en.wikipedia.org/wiki/Dependency_injection#Java
Same answer as above. The thing with dependency injection is in inversion of control. A class that uses MyMethods
does not know about actual the implementation of MyMethods
, but the injection of real implementation is delegated to some higher-level authority. It abstracts external dependencies from the context where it is going to be used. Again, if MyMethods
are to be stateless and constant (not planned to change, and the behavior of methods within the class does not depend on the context where they are used) you do not need these patterns as it would just mean over engineering.
I would conclude that you should use Strategy or DI pattern if logic of MyMethods
depends on the context from which they are run. If this is constant (e.g. Java's Math
class does not care who or in what context someone calls sqrt()
, max()
or pow()
) then static methods are the way to go.
Regarding problems:
Problems you stated are not present when you use MyMethods
with static
methods. You will have to test whether your methods return correct values for particular arguments and that's it. I don't believe that there would be much more trouble testing actual implementation of Strategy
in Strategy pattern or implementation of interface that are injected through Dependency injection. What might be harder is testing the classes that use strategy because sometimes it's not easy to recreate the context in which particular strategy will be executed as it often depends on user input, but it's definitely not impossible. Dependency injection is, as far as I'm concerned, great for testing because you can separate unit under test from dependency which you can easily mock.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With