The prototype derivation of IoC thought, whose control is reversed to whom

1. Basic concepts of IoC

Inversion of Control (IoC) is a design principle in object-oriented programming, which can be used to reduce the coupling between computer codes. Through control inversion, when an object is created, the external entities of all objects in a control system pass the references of the objects it depends on to it. In other words, dependencies are injected into objects.

——From Baidu Encyclopedia

2. Derivation

Obviously, the above concept seems abstract, so we have to point out a question: "control reversal" reverses whose control right and gives it to who?

To put it bluntly, the main control power of the traditional program lies in the program itself, which is hard coded into the program by the programmer. In other words, it can also be said that it is controlled by the programmer. The requirements of customers are constantly changing. Whenever new requirements are proposed, the tool person in charge of the program needs to modify the source code to meet the needs of users, which leads to a high degree of code coupling. "Why don't we give control to users?", at this time, the idea of inversion of control (IoC) came into being.

The right to create an object is transferred from the programmer to the user, who decides the specific object to be generated.

3. Prototype code implementation

Here's a simple example: when you don't know what database users choose to read user data (of course, this is just an example)

Traditional implementation

Structure:

DAO layer:

public interface UserDao {
    String getUser();
}

public class UserDaoImpl implements UserDao{
    @Override
    public String getUser() {return "Get users using default database";}
}

public class UserDaoMysqlImpl implements UserDao{
    @Override
    public String getUser() {return "use Mysql Database get user";}
}

public class UserDaoOracleImpl implements UserDao{
    @Override
    public String getUser() {return "use Oracle Database get user";}
}

Service layer:

public interface UserService {
    void getUser();
}

public class UserServiceImpl implements UserService{
    //In the traditional use of interfaces, the source code needs to be modified every time there are new requirements
    //When the user wants to use the default method
    private UserDao userDao=new UserDaoImpl();
    //When users want to use Mysql
    //private UserDao userDao=new UserDaoMysqlImpl();
    //When users want to use Oracle
    //private UserDao userDao=new UserDaoOracleImpl();
    //When users want to use
    
    //Since hard coding is adopted (i.e. writing dead code), it is necessary to constantly modify the source code when the user's needs are uncertain
    
    @Override
    public void getUser() {
        System.out.println(userDao.getUser());
    }
}

Test:

@Test
public void MyTest():{
    UserServiceImpl userService=new UserServiceImpl();
   	userService.getUser();
}

The Console displays:

"C:\Program Files\Java\jdk1.8.0_281\bin\java.exe" ...
Get users using default database

Process finished with exit code 0

As mentioned above, the disadvantage of this traditional factory mode is that the creation of objects is completely hard coded in the program, and the creation of objects will be controlled by the program. At this time, once the requirements change, the source code needs to be modified.

IoC prototype implementation

The project structure remains unchanged

DAO layer (unchanged):

public interface UserDao {
    String getUser();
}

public class UserDaoImpl implements UserDao{
    @Override
    public String getUser() {return "Get users using default database";}
}

public class UserDaoMysqlImpl implements UserDao{
    @Override
    public String getUser() {return "use Mysql Database get user";}
}

public class UserDaoOracleImpl implements UserDao{
    @Override
    public String getUser() {return "use Oracle Database get user";}
}

Service layer:

public interface UserService {
    void getUser();
}

public class UserServiceImpl implements UserService{
    
    private UserDao userDao;
	//Dynamic value injection by set method
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    
    @Override
    public void getUser() {
        System.out.println(userDao.getUser());
    }
}

Test:

@Test
public void MyTest():{
    UserServiceImpl userService=new UserServiceImpl();
    UserDao userDao=null;
    //Which method you want to use now will depend on the user's choice
    System.out.println("1.I want to use the default method to get user data");
    System.out.println("2.I want to use mysql To get user data");
    System.out.println("3.I want to use Oracle To get user data");
    Scanner sc=new Scanner(System.in);
    System.out.print("================\n Enter your choice:");
    int choice = sc.nextInt();
    switch (choice) {
        case 1:userDao = new UserDaoImpl();break;
        case 2:userDao = new UserDaoMysqlImpl();break;
        case 3:userDao = new UserDaoOracleImpl();break;
        default:break;
    }
    userService.setUserDao(userDao);
    userService.getUser();
}

The Console displays:

"C:\Program Files\Java\jdk1.8.0_281\bin\java.exe" ...
1.I want to use the default method to get user data
2.I want to use mysql To get user data
3.I want to use Oracle To get user data
================
Enter your choice: 2
 use Mysql Database get user

Process finished with exit code 0

At this time, it can be found that by adding a set method in the DAO layer, dynamic value injection can be realized, and the control of object creation can be transferred to the user, which does not need us to modify

4. Summary

Traditional implementation and IoC control inversion prototype implementation:

Careful brother may find that the above mentioned are only the prototype implementation of IoC, which is not the "complete body" of IoC. Here is mainly to show you the idea of IoC. On the surface, the above implementation alleviates the above problems to a certain extent, but in essence, this code coupling has not changed. This coupling can be completely solved through IoC mode. It removes the coupling from the code, puts it into a unified XML file, and forms the dependency when needed through a container, that is, injects the required interface implementation into the classes that need it. This may be the source of the term "dependency injection".

Moreover, does this IoC mode remind you of a familiar Java feature - reflection, which uses Java's "reflection" programming to generate corresponding objects according to the class definitions given in XML. From the implementation point of view, for the objects previously written in the factory mode, the IoC mode is changed to the configuration XML file, which isolates the factory from the objects to be generated, greatly improving the flexibility and maintainability.

Tags: Java Spring reflection ioc

Posted on Wed, 13 Oct 2021 11:01:13 -0400 by dreamkiller23