spring01-引入

耦合


  1. 什麼是耦合?
    • 耦合表示類與類之間的聯繫, 類與類之間的聯繫越強, 耦合度越高
  2. 經過例子來講明
    • 咱們寫了兩個類, 其中beanService中須要用到beanDao來實現功能
      • beanDao接口和實現類git

        public interface BeanDao {
            // 模擬add方法
            void add();
        }
        
        public class BeanDaoImpl implements BeanDao {
            @Override
            public void add() {
                System.out.println("添加bean信息");
            }
        }
      • beanService接口和實現類github

        public interface BeanService {
            void add();
        }
        
        public class BeanServiceImpl implements BeanService {
            BeanDao dao = new BeanDaoImpl();
            @Override
            public void add() {
                dao.add();
            }
        }
      • 測試類及運行結果spring

        public class Demo {
            @Test
            public void demo01() {
                BeanService service = new BeanServiceImpl();
                service.add();
            }
        }

        運行結果

      • 從代碼結構中能夠看出: beanService中沒有beanDao的耦合度很高, 若是沒有BeanDao的實現類, 編譯時就會報錯ide

    • 改造一下, 咱們能夠用工廠模式來解耦
      • 工廠類代碼:測試

        public class BeanFactory {
            public static Object getInstance(String className) {
                try {
                    Class<?> clazz = Class.forName(className);
                    Object obj = clazz.newInstance();
                    return obj;
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        }
      • 有了工廠類代碼之後咱們就能夠改造一下beanServiceImpl線程

        public class BeanServiceImpl implements BeanService {
            BeanDao dao = (BeanDao) BeanFactory.getInstance("cn.ann.dao.impl.BeanDaoImpl");
        
            @Override
            public void add() { dao.add(); }
        }
      • 運行結果仍是同樣的code


      • 經過改造, BeanServiceImpl和BeanDaoImpl的耦合已經下降, 最直觀的效果就是若是沒有BeanDaoImpl這個類的話, 程序在編譯期間不會報錯
      • 可是, 還有一些問題: className是寫死的, 若是咱們的實現類不在這個路徑, 或者是不叫這個名字, 就沒辦法經過工廠獲取這個類的對象了


  • 繼續改造, 加配置文件是不錯的選擇
    • 配置文件bean.properties對象

      beanDao=cn.ann.dao.impl.BeanDaoImpl
    • beanFactoryblog

      public class BeanFactory {
          private static Map<String, String> props = new HashMap<>();
      
          static {
              try (InputStream is = BeanFactory.class.getClassLoader().
                      getResourceAsStream("bean.properties")) {
                  Properties prop = new Properties();
                  prop.load(is);
                  Set<String> keys = prop.stringPropertyNames();
                  keys.forEach((key) -> props.put(key, prop.getProperty(key)));
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          public static Object getInstance(String key) {
              if (props.containsKey(key)) {
                  try {
                      Class<?> clazz = Class.forName(props.get(key));
                      Object obj = clazz.newInstance();
                      return obj;
                  } catch (Exception e) {
                      e.printStackTrace();
                      return null;
                  }
              } else {
                  throw new RuntimeException("配置文件中不存在該key");
              }
          }
      }
      • 經過改造, 咱們能夠將BeanServiceImpl中成員變量的初始化改爲BeanDao dao = (BeanDao) BeanFactory.getInstance("beanDao");

    • 經過加配置文件, 咱們能夠經過修改配置文件的方式來修改BeanDao的實現類. 那麼還有什麼問題呢?
      • 若是出現了頻繁使用beanServiceImpl的場景的話, 咱們是否是要建立不少類呢? 或許咱們可讓建立出來的對象成爲單例的


  • 再次改造
    • BeanFactory接口

      public class BeanFactory {
          private static Map<String, Object> instances = new HashMap<>();
      
          static {
              try (InputStream is = BeanFactory.class.getClassLoader().
                      getResourceAsStream("bean.properties")) {
                  Properties prop = new Properties();
                  prop.load(is);
                  Set<String> keys = prop.stringPropertyNames();
                  keys.forEach((key) -> {
                      try {
                          instances.put(key, Class.forName(prop.getProperty(key)).newInstance());
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  });
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          public static Object getInstance(String key) {
              if (instances.containsKey(key)) {
                 return instances.get(key);
              } else {
                  throw new RuntimeException("配置文件中不存在該key");
              }
          }
      }
    • 運行結果:
      運行結果
      • 經過運行結果能夠看出, BeanDaoImpl是同一個對象

本篇到此結束, 這篇文章的重點是關於耦合這方面的, 因此並無考慮關於線程的問題
本篇代碼下載連接: 點擊此處 的 spring01-introduce

相關文章
相關標籤/搜索