实现功能:小黄开奥迪上班/下班
要求:可维护,可复用,可扩展,灵活性好
第一版
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 Mapcontainer = 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