程序解耦合思想,关于spring IOC,DI

程序解耦合思想

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调 用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关
系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立 性)。耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。 在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计
应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个 准则就是高内聚低耦合。

程序的耦合

耦合:程序间的依赖关系

包括:类之间的依赖,方法间的依赖

解耦:降低程序间的依赖关系

实际开发中:应该做到:编译期不依赖,运行时才依赖。

解耦的思路:

第一步:使用反射来创建对象,而避免使用new关键字。

第二步:通过读取配置文件来获取要创建的对象全限定类名

例如:使用DriverManager.registerDriver(new com.mysql.jdbc.Driver()); 语句,如果没有对应的依赖,在编译期就会报异常,所有使用Class.forName("com.mysql.jdbc.Driver"); 用反射的方式读取配置文件,降低耦合度

public class JdbcDemo1 {
    public static void main(String[] args) throws  Exception{
        //1.注册驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        //Class.forName("com.mysql.jdbc.Driver");

        //2.获取连接
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/eesy","root","1234");
        //3.获取操作数据库的预处理对象
        PreparedStatement pstm = conn.prepareStatement("select * from account");
        //4.执行SQL,得到结果集
        ResultSet rs = pstm.executeQuery();
        //5.遍历结果集
        while(rs.next()){
            System.out.println(rs.getString("name"));
        }
        //6.释放资源
        rs.close();
        pstm.close();
        conn.close();
    }
}

以下代码,private IAccountDao accountDao = new AccountDaoImpl(); 如果dao层没有对应的实现类,那么就会发生编译时异常,程序耦合度高,不够健壮

public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao = new AccountDaoImpl();

    //private IAccountDao accountDao = (IAccountDao)BeanFactory.getBean("accountDao");

//    private int i = 1;

    public void  saveAccount(){
        int i = 1;
        accountDao.saveAccount();
        System.out.println(i);
        i++;
    }
}

首先配置一个properties文件

accountService=com.itheima.service.impl.AccountServiceImpl
accountDao=com.itheima.dao.impl.AccountDaoImpl
/**
 * 一个创建Bean对象的工厂
 *
 * Bean:在计算机英语中,有可重用组件的含义。
 * JavaBean:用java语言编写的可重用组件。
 *      javabean >  实体类
 *
 *   它就是创建我们的service和dao对象的。
 *
 *   第一个:需要一个配置文件来配置我们的service和dao
 *           配置的内容:唯一标识=全限定类名(key=value)
 *   第二个:通过读取配置文件中配置的内容,反射创建对象
 *
 *   我的配置文件可以是xml也可以是properties
 */
public class BeanFactory {
    //定义一个Properties对象
    private static Properties props;

     //使用静态代码块为Properties对象赋值
    static {
        try {
            //实例化对象
            props = new Properties();
            //获取properties文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
            }
        }catch(Exception e){
            throw new ExceptionInInitializerError("初始化properties失败!");
        }
    }


 public static Object getBean(String beanName){
        Object bean = null;
        try {
            String beanPath = props.getProperty(beanName);
            System.out.println(beanPath);
            bean = Class.forName(beanPath).newInstance();//每次都会调用默认构造函数创建对象
        }catch (Exception e){
            e.printStackTrace();
        }
        return bean;
    }
   
}

单例模式

public class BeanFactory {
    //定义一个Properties对象
    private static Properties props;

    //定义一个Map,用于存放我们要创建的对象。我们把它称之为容器
    private static Map<String,Object> beans;

    //使用静态代码块为Properties对象赋值
    static {
        try {
            //实例化对象
            props = new Properties();
            //获取properties文件的流对象
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            props.load(in);
            //实例化容器
            beans = new HashMap<String,Object>();
            //取出配置文件中所有的Key
            Enumeration keys = props.keys();
            //遍历枚举
            while (keys.hasMoreElements()){
                //取出每个Key
                String key = keys.nextElement().toString();
                //根据key获取value
                String beanPath = props.getProperty(key);
                //反射创建对象
                Object value = Class.forName(beanPath).newInstance();
                //把key和value存入容器中
                beans.put(key,value);
            }
        }catch(Exception e){
            throw new ExceptionInInitializerError("初始化properties失败!");
        }
    }

    /**
     * 根据bean的名称获取对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName){
        return beans.get(beanName);
    }

}

[图片上传失败...(image-ec806-1596714253764)]

[图片上传失败...(image-b3347b-1596714253764)]

IOC

实例化 Bean 的三种方式

第一种方式:使用默认无参构造函数

第二种方式:spring管理静态工厂-使用静态工厂的方法创建对象 /**

模拟一个静态工厂,创建业务层实现类 */ public class StaticFactory { public static IAccountService createAccountService(){ return new AccountServiceImpl(); } }

第三种方式:spring管理实例工厂-使用实例工厂的方法创建对象 /**

模拟一个实例工厂,创建业务层实现类 * 此工厂创建对象,必须现有工厂实例对象,再调用方法 */ public class InstanceFactory { public IAccountService createAccountService(){ return new AccountServiceImpl(); } }

 <!--在默认情况下:   它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。--> 
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>  


<!-- 此种方式是:   使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器   id 属性:指定 bean 的 id,用于从容器中获取   class 属性:指定静态工厂的全限定类名   factory-method 属性:指定生产对象的静态方法  --> 
<bean id="accountService"  
   class="com.itheima.factory.StaticFactory"     factory-method=" createAccountService"></bean> 
 

 <!-- 此种方式是:    先把工厂的创建交给 spring 来管理。   然后在使用工厂的 bean 来调用里面的方法   factory-bean 属性:用于指定实例工厂 bean 的 id。   factory-method 属性:用于指定实例工厂中创建对象的方法。  --> 

<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean> 

<bean id="accountService"      factory-bean="instancFactory"      factory-method="createAccountService"></bean> 

DI

依赖注入的概念

依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。 我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。 ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。 那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。 简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

构造函数注入
顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置
的方式,让 spring 框架来为我们注入。

public class AccountServiceImpl implements IAccountService {    
    private String name; 
    private Integer age;  
    private Date birthday;
    
    public AccountServiceImpl(String name, Integer age, Date birthday) {
        this.name = name;  
        this.age = age;   
        this.birthday = birthday;  
    } 
 
    @Override  
    public void saveAccount() {  
        System.out.println(name+","+age+","+birthday);   
    }
} 
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> 
 <constructor-arg name="name" value=" 张三 "></constructor-arg>  <constructor-arg name="age" value="18"></constructor-arg> 
 <constructor-arg name="birthday" ref="now"></constructor-arg> 
</bean> 

set 方法注入

顾名思义,就是在类中提供需要注入成员的 set 方法

public class AccountServiceImpl implements IAccountService {    
    private String name;  
    private Integer age;  
    private Date birthday;    
    public void setName(String name) {   
        this.name = name;  
    }  
    public void setAge(Integer age) {   
        this.age = age;  
    }  
    public void setBirthday(Date birthday) {
        this.birthday = birthday;  
    } 
 
    @Override  
    public void saveAccount() {
        System.out.println(name+","+age+","+birthday);   
    } 
} 
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">   
    <property name="name" value="test"></property> 
    <property name="age" value="21"></property>   
    <property name="birthday" ref="now"></property> 
</bean>

注入集合属性

顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。

public class AccountServiceImpl implements IAccountService {
    private String[] myStrs;  
    private List<String> myList;  
    private Set<String> mySet;  
    private Map<String,String> myMap;  
    private Properties myProps;    
    public void setMyStrs(String[] myStrs) { 
        this.myStrs = myStrs;  
    }  
    public void setMyList(List<String> myList) { 
        this.myList = myList;  
    }  
    public void setMySet(Set<String> mySet) {   
        this.mySet = mySet; 
    }  
    public void setMyMap(Map<String, String> myMap) { 
        this.myMap = myMap; 
    }  
    public void setMyProps(Properties myProps) { 
        this.myProps = myProps;  
    } 
 
     @Override 
    public void saveAccount() {
        System.out.println(Arrays.toString(myStrs));  
        System.out.println(myList);  
        System.out.println(mySet);  
        System.out.println(myMap);   
        System.out.println(myProps); 
    }
} 
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
    <!-- 在注入集合数据时,只要结构相同,标签可以互换 -->  
    <!-- 给数组注入数据 -->  
    <property name="myStrs"> 
        <set>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </set> 
    </property> 
    <!-- 注入 list 集合数据 -->  
    <property name="myList">   
        <array>    
            <value>AAA</value>    
            <value>BBB</value>    
            <value>CCC</value>   
        </array>  
    </property> 
     <!-- 注入 set 集合数据 -->  
    <property name="mySet">
        <list>    
            <value>AAA</value>    
            <value>BBB</value>    
            <value>CCC</value>   
        </list>  
    </property> 
    <!-- 注入 Map 数据 -->  
    <property name="myMap">   
        <props> 
            <prop key="testA">aaa</prop>    
            <prop key="testB">bbb</prop>   
        </props> 
    </property> 
    <!-- 注入 properties 数据 -->
     <property name="myProps"> 
        <map>    
            <entry key="testA" value="aaa"></entry> 
            <entry key="testB">    
                <value>bbb</value> 
            </entry>   
         </map>  
    </property> 
</bean>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350