Code Reuse in Methods.class vs. Strategy Pattern and Dependency Injection

Status: answers of Fendy and Glen Best are equally acceptable and respected by me, but since I can accept and receive the award, I choose the answer of Fendy.

Scenario:

If I have some code that is reused many times in many classes (rarely with minor parameter changes that are obvious) and parallel threads, which approach should I go to?

The code that needs to be reused can be any reasonable thing (with proper attention to the static and unsteady context in mind and methods of creating methods). It can be an algorithm, a database method that performs a connection, work, closure. Everything.

  • Make a class like MyMethods.class and put all of these methods into it .

    1.a. Make methods static and call (across all classes and parallel threads) directly as MyMethods.someMethod();

    1b. Make the methods non-static and at the time to call them instantiate whole class on MyMethods mm = MyMethods(); mm.someMethod(); MyMethods mm = MyMethods(); mm.someMethod();

  • Use the Strategic Template specified at https://en.wikipedia.org/wiki/Strategy_pattern (code is provided here).

  • Use the dependency injection specified at https://en.wikipedia.org/wiki/Dependency_injection#Java

Problems:

  • Some people will say Unit test http://en.wikipedia.org/wiki/Unit_testing will not be possible with this approach, will make the problem of replacing the latter. if you want to test your class and use the mock version of the dependency

    1.a. Will there be problems with calling simultaneous or multiple classes? especially in JDBC static methods for example?

    1b. I think this would put too much strain on the memory , as the whole class < would be instanticated many times just to call one or two methods

  • What happens above my head, explain this and / or advantages / disadvantages

  • Do not use the framework in the context of this question. This is much better than explaining it and any advantages / disadvantages.
  • Waiting for any other strategies or recommendations, if any.

Request: Please answer only if you are experienced and know the consequences 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 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 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 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 ); } } 
+8
java design-patterns dependency-injection class unit-testing
source share
3 answers

In fact, your question has two meanings.

which should be reused in many classes

This can be the context of a design pattern (reusable component) or memory (instantiation of a class). Speaking from two different points of view:

The cost of memory (I have little experience with this, but let me share my experience)

This section actually covers only 2 types of instance.

Static first (or creating DI at the root of the composition)

  • Bright instance creation means that the whole class will be created when the application starts
  • One-time instantiation only

Non-static

  • Lazy instantiation, means that the class will be created only if necessary
  • Once for each use

In short, a static one will be expensive if the class is many, and a non-static one will be expensive if the request is high (for example, inside a loop). But this should not make your application heavy. Most operations in java / csharp create objects.

Class reuse

1 - mega monolithic code (one class of gods is able to do almost everything)

Benefits:

  • It’s easy to search for the code (it still depends on that), you know that every logic lies there, so you just need to look at this large class.
  • If it's static, you can just call it anywhere without worrying about instantiating

Disadvantages:

  • Any modification to one method creates a risk of error in other places.
  • Violates SRP, means that this class can be changed for various reasons, not just one
  • In particular, when managing versions, it is more difficult to combine if the modification occurs in separate branches, which leads to increased code synchronization

1a / static class / single template

Benefits:

  • Ease of use
  • Can be used anywhere (link, call and execution only)
  • No need to instantiate an object

Disadvantages:

  • It’s difficult to unit test (it’s difficult to mock, and recently you find that it takes time to prepare the test environment. Especially with the data
  • If the state is a state (state), it is difficult to determine the current state during debugging. In addition, it is difficult to determine which function changes the state in which it can be changed everywhere.
  • As a rule, there are many parameters (perhaps around 5-11).

Some point about static class: see this question

2 strategy template

Actually it has the same design with 3 or composition over inheritance .

3 dependency injections

Benefits:

  • Easy to mock and unit test
  • Must be stateless . It is easier to debug and unit test if the class has no status.
  • Support for refactoring

Disadvantage:

  • It’s hard to debug those who are not familiar with the interfaces (every time you redirect a method, it goes to the interface)
  • Creates a layering that will display

State / stateless

I think that states play important rules in the design of your application. Typically, developers try to avoid the presence of states in the code of business logic, for example:

 // get data if(request.IsDraft){ // step 1 // step 2 } else{ // step 1 // step 3 } 

Developers tend to put logic in another stateless class, or at least methods such as:

 // get data if(request.IsDraft){ draftRequestHandler.Modify(request); } else{ publishedRequestHandler.Modify(request); } 

It will provide better readability and simplify modification and unit tests. There is one state pattern or hierarchial state machine pattern design template, especially for handling such cases.

Principle of shared responsibility

IMHO, this principle has the greatest benefit, if followed. Benefits:

  • In the version change it is clear which class has been changed and why
  • In DI, you can connect several smaller classes, creating flexibility both in use and in unit test
  • Increased modularity, low grip and high grip

TDD (Test Driven Development)

This design does not guarantee that your code will not contain errors. In minus the estimated time at the design stage and overlay it has the advantage of:

  • Easy mock object for unit test
  • Easier to refactor due to unit test and modularity
  • Easier to maintain / expand

Some useful sources

Locator Anti-Virus Antivirus Software

Using Decorator for end-to-end care

My 2 cents:

The advantage of using an interface (also used for composing inheritance)

Perform Design Design / DI Down

Final thoughts

These projects and strategies are not the key that will determine your application structure. He is still the architect who will define him. I prefer to follow some principles, such as SOLID, KISS and GRASP, instead of deciding what is the best structure. Injection Dependency is said to adhere to most of these principles, but too much abstraction and improper component design will result in the same misuse of a singleton pattern.

+8
source share

1.a. Make methods static and call (with all classes and parallel threads) directly as MyMethods.someMethod ();

1b. Make methods non-static and call them at that time, create an instance of the entire class using MyMethods mm = MyMethods (); mm.someMethod ();

The choice between these two options depends on the functionality of MyMethods.class . If MyMethods assumed to be stateless, then this is a good approach for using static methods. Otherwise, if the call to one method depends on another, and the MyMethods state depends on the state (i.e. non-final fields), then use the second option.

Use the strategy template specified at https://en.wikipedia.org/wiki/Strategy_pattern (the code is here).

Use this template if MyMethods needs to be extended with different classes for different purposes, and if you choose which code will run depending on your context. As the wiki says, if you use an algorithm unknown before runtime (depends on some conditions), this is the way to go. According to your MyMethods specification, you have no such problems.

Use the dependency injection specified at https://en.wikipedia.org/wiki/Dependency_injection#Java

Same answer as above. The thing with dependency injection is control inversion. The class that MyMethods uses MyMethods not know about the actual implementation of MyMethods , but the injection of the actual implementation is delegated to some higher-level authorities. It abstracts external dependencies on the context in which it will be used. Again, if MyMethods should be constant and constant (don't plan to change, and the behavior of the methods inside the class does not depend on the context in which they are used), you do not need these templates, as that would simply mean over engineering ones.

I would conclude that you should use a strategy or DI pattern if the logic of MyMethods depends on the context from which they are executed. If this is a constant (for example, the Java Math class does not care about who or in what context someone calls sqrt() , max() or pow() ), then static methods are the way to go.


Regarding the problems:

There are no problems you have MyMethods if you use MyMethods with static methods. You will need to check if your methods believe the correct values ​​for specific arguments and what they are. I do not believe that there would be much more problems testing the actual implementation of Strategy in a strategy template or implementation of an interface that is introduced through dependency injection. Which may be more difficult to validate classes that use a strategy, because sometimes it is not easy to recreate the context in which a particular strategy will be executed, since it often depends on user input, but it is definitely not impossible. The injection dependency, as far as I know, is great for testing, because you can separate the unit being tested from the dependency, which you can easily make fun of.

+3
source share
  • Main Question: Code Reuse

    If I have code that needs to be reused many times in many classes (rarely with minor parameter changes that are obvious) and parallel threads, which approach is suitable for?

    Since you are not considering any cut-off and amputation, I think you mean:

    ... many times many times used by many classes ...

    What you ask for is nothing special or specific. It is well known that code is reused either in one application or in multiple applications. General answer: use object-oriented design / programming . Put the code in the class, create the object as an instance, call the object ...

    1a. Reuse with static methods:

    Make static and call methods (all classes and parallel threads) directly as MyMethods.someMethod ()

    • If your class has no state (without instance variables), this is a great approach.
    • If your class has a class level state (only static instance variables), but the variables are read-only (immutable), this is a good approach.
    • If your class has a class level state (only static instance variables) and the variables change the values ​​(mutable), then this may be the appropriate approach. However, if you want your class to be accessible from several threads, you should make it thread safe: synchronize your methods or have an internal code that synchronizes (mutually exclusive thread) for all data read and write.
    • If your code has an object level state (non-static instance variables), this approach will not work - it is impossible to access non-statistical instance variables without instantiating the object.

    1b. Reuse with non-static methods with object creation:

    Make the methods non-static and call them at that time, create an instance of the entire class MyMethods mm = MyMethods (); mm.someMethod ();

    • If your class has only static instance variables, this is a bad approach because the instance of the object does not achieve anything
    • If your class has non-static instance variables, this is the only approach. Be sure to create an instance of the object to access the variables.
    • If the created objects should be used for several threads, they should be (in order of preference):
      • stateless (no instance variables) - really an option for 1a - no need to instantiate
      • immutable (read-only non-static instance variables)
      • synchronized in all reads and data records
  • Use strategy template.

    Strategy can be good practice. But this has nothing to do with your general question. The strategic template is used for a specific reason - to replace the implementation of the processing algorithm / logic on the fly without affecting the caller.

  • Use dependency injection

    For these reasons, dependency injection is used:

    • Factory and object cache functionality: removes responsibility for creating an object, caching and searching from your code
    • Intermediate interaction for sharing objects: allows different classes to share the same instance of the object (stored in a given area / context), without two classes directly transferring the object to each other.
    • "Wiring management" between instances of objects - setting up associations of objects and under CDI, support for interceptor patterns, decorators and observers.

    This can be very good practice if used properly. In your case, this can only apply in case of option 1b. Dependency injection is all about creating objects and providing variables.

Problems:

  • Some people will say that unit test will not be possible.

    • Mocking frameworks (and unit-coded unit testing) are constantly replacing classes with layout logic. This is a very common scenario. You can extend a class to make fun of its logic - if it does not have final public methods. In addition, you can pass declarations to methods in an interface, have a class that implements the interface, and then mock it by injecting the interface into another class.
    • In other words, this is not a limitation / force affecting any of your parameters.

    1a. See above

    1b. Load memory

    I think this would put too much strain on the memory, since the whole class would run multiple times to call one or two methods.

    Little problem. Depending on the data in each instance of the object (instance variables), each instance of the object can be a size from a dozen bytes or up to a megabyte, but is usually tilted to the lower end (often <1kB). The memory consumption of the class code itself is not replicated every time an instance of the class is created.

    Of course, it’s good practice to minimize the volume of objects in accordance with your requirements - do not create a new instance if you already have a useful one. Create fewer instances of objects and share them in your application - pass them to constructor methods and customization methods. Enabling dependencies is a good way to share instances of objects "automatically" without passing them to constructors / setters.

  • See above

  • See above

+3
source share

All Articles