实现简单的IOC容器(ByName)

实现功能:小黄开奥迪上班/下班
要求:可维护,可复用,可扩展,灵活性好
第一版
Audi
 1 public class Audi {
 2 
 3     public void start() {
 4         System.out.println("启动奥迪");
 5     }
 6 
 7     public void shutDown() {
 8         System.out.println("启动奥迪");
 9     }
10 
11     public void turnLeft() {
12         System.out.println("奥迪左转");
13     }
14 
15     public void turnRight() {
16         System.out.println("奥迪右转");
17     }
18 }

人类

 1 public class Person {
 2 
 3     void goHome() {
 4         Audi audi = new Audi();
 5         audi.start();
 6         audi.turnLeft();
 7         audi.turnRight();
 8         audi.shutDown();
 9     }
10 
11     void goWork() {
12         Audi audi = new Audi();
13         audi.start();
14         audi.turnRight();
15         audi.turnLeft();
16         audi.shutDown();
17     }
18 
19     void aNormalDay()
20     {
21         System.out.println("新的一天开始啦");
22         System.out.println("------------");
23         System.out.println("去工作");
24         goWork();
25         System.out.println("------------");
26         System.out.println("回家");
27         goHome();
28         System.out.println("------------");
29         System.out.println("一天结束啦");
30     }
31 }

测试代码

1 public static void main(String[] args) {
2         Person xiaoHuang=new Person();
3         xiaoHuang.aNormalDay();
4     }
缺点:
1.是人类对象创建的奥迪车
(1)不是每个人都有车(考虑将有车的人继承与普通人/或者把回家,工作的行为抽象成接口,由不同的人来实现)
(2)不是每个人有车的人都是奥迪(考虑将汽车抽象出来)
2.小黄如果要换车的话,需要修改代码过多
3.小黄new了两次奥迪车,其实应该是同一辆奥迪车(考虑把局部变量,变为类的私有属性)

违反 单一职责原则(人类创建车)
开闭原则(需要修改代码)
面向接口(都是实现类,没有使用接口)


第二版

汽车抽象类
1 public abstract class Car {
2     public abstract void start();
3 
4     public abstract void shutDown();
5 
6     public abstract void turnLeft();
7 
8     public abstract void turnRight();
9 }
Audi
 1 // 奥迪车世界上有很多辆
 2 // 所以应该是类,每个奥迪车应该是对象
 3 // 人这不一样,每个人都是一个单独的对象
 4 // 所以判断该成对象还是类的时候可以想象是单数还是复数
 5 // 单数则是对象,复数则是类
 6 public class Audi extends Car{
 7     @Override
 8     public void start() {
 9         System.out.println("启动奥迪");
10     }
11 
12     @Override
13     public void shutDown() {
14         System.out.println("启动奥迪");
15     }
16 
17     @Override
18     public void turnLeft() {
19         System.out.println("奥迪左转");
20     }
21 
22     @Override
23     public void turnRight() {
24         System.out.println("奥迪右转");
25     }
26 }
BMW
 1 public class BMW extends Car{
 2     @Override
 3     public void start() {
 4         System.out.println("启动宝马");
 5     }
 6 
 7     @Override
 8     public void shutDown() {
 9         System.out.println("启动宝马");
10     }
11 
12     @Override
13     public void turnLeft() {
14         System.out.println("启动宝马");
15     }
16 
17     @Override
18     public void turnRight() {
19         System.out.println("启动宝马");
20     }
21 }

抽象人类

 1 public abstract class Person {
 2     abstract void goHome();
 3     abstract void goWork();
 4     //设计模式:模板模式
 5     public void aNormalDay()
 6     {
 7         System.out.println("新的一天开始啦");
 8         System.out.println("------------");
 9         System.out.println("去工作");
10         goWork();
11         System.out.println("------------");
12         System.out.println("回家");
13         goHome();
14         System.out.println("------------");
15         System.out.println("一天结束啦");
16     }
17 }

有车一族

 1 public class PersonWithCar extends Person{
 2     //优点
 3     //1这个car不应该有人类创建,而是通过传入指定的car
 4     //2回家,工作使用的是同一辆车
 5     //3换车不需要修改代码,遵守开放闭合原则
 6     private Car car;
 7 
 8     public PersonWithCar(Car car) {
 9         this.car = car;
10     }
11 
12 
13     @Override
14     void goHome() {
15         car.start();
16         car.turnRight();
17         car.turnLeft();
18         car.shutDown();
19     }
20 
21     @Override
22     void goWork() {
23         car.start();
24         car.turnRight();
25         car.turnLeft();
26         car.shutDown();
27     }
28 }
小黄开奥迪上班/下班
小张开宝马上班/下班
模板模式
优点
1这个car不应该有人类创建,而是通过传入指定的car
2回家,工作使用的是同一辆车
3换车不需要修改代码,遵守开放闭合原则
4.设置每个人的一天(上班,回家)的抽象,通过对不同交通工具的人来具体实现(模板模式)

IOC容器版
 1 public class MyIocContainer {
 2 
 3     //保证只被初始化一次
 4     //跟随类的初始化而初始化
 5     private static Map<String, Object> container = new ConcurrentHashMap<>();
 6 
 7     public Object getBean(String id) {
 8         return container.get(id);
 9     }
10 
11     public void setBean(Class<?> clazz, String beanId, String... paramBeanId) {
12         //通过id获取所有在bean容器的实例
13         Object[] objects = new Object[paramBeanId.length];
14         for (int i = 0; i < paramBeanId.length; i++) {
15             objects[i] = getBean(paramBeanId[i]);
16         }
17 
18         //使用不同的构造函数构造,最终只有一个能够成功
19         Object bean = null;
20         for (Constructor constructor : clazz.getConstructors()) {
21             try {
22                 bean = constructor.newInstance(objects);
23             } catch (InstantiationException e) {
24             } catch (IllegalAccessException e) {
25             } catch (InvocationTargetException e) {
26             }
27         }
28         if (bean == null)
29             throw new RuntimeException("实例化失败");
30         container.put(beanId, bean);
31     }
32 }
很明显这次的IOC容器使用的模式是使用ByName,名字匹配类型(查阅资料发现ByName效率的确比ByType高,所有对使用@resource的byName)
写了这个demo后对倚赖注入,反转控制有了更深的理解
倚赖注入是目标:通过从容器注入bean,对象间的聚合和合成关系,是一种弱耦合的关系
反转控制是手段:通过bean容器来控制bean的生命周期

   在容器中对象的创建只会创建一次(singleton模式下),如果name指定不对,就会出现bean注入失败的错误(我经常犯的错QAQ)

1.控制bean的生命周期指的不是类加载,指的是控制对象bean的生命周期
原来:客户端管理车的生产,现在由容器管理
优点:大大解耦类与类的倚赖
2.所有的对象都由容器管理
优点:解耦,每个类只关注自己的业务逻辑

代码地址:https://gitee.com/gang_bryant/DesignMode/tree/master/src/MyIoc


 
原文地址:https://www.cnblogs.com/Gang-Bryant/p/10896440.html