夜光带你走进 Java 成神之路(二十二)擅长的领域

夜光序言:

 

 

 

 

做人需简单,不沉迷幻想,不茫然未来,走今天的路,过当下的生活。

 

 

 

 

 

 

 

 

正文:

                           以道御术 / 以术识道

 

 

介绍Spring IOC容器,通过具体的实例详细地讲解IOC概念,彻底理解Spring反转控制的思想。

通过本篇的学习,可以达成如下目标。

● 运用工厂模式设计程序  【设计模式要烂熟于心~~】

● 理解JavaBean和POJO对象

● 理解控制反转思想

● 理解IOC容器

 

 

1、来介绍一下:简单的项目需求

在一个Genius Team 程序员培训班,一天只上三节课,有三名老师和一个校长。

萧炎负责教学生java

林动教学生数C#

唐三教python

 

校长负责安排三位老师每天的上课时间,并提前通知各位老师上课时间,通知方式包括邮件、电话,后续可能会有更多方式。

现在需要编写一个Java程序实现校长安排老师老师上课时间,并通知到老师,要考虑程序的可扩展性。

 


2、用工厂模式设计程序

项目中通知老师上课的方式包括邮件、电话,后续可能还有所扩展。

虽然通知方式不同,但通知功能是一致的,适合用工厂模式来设计通知功能,后续增加通知方式时,再增加一个通知实现类和修改工厂类代码就可以了,无需修改其它实现类的代码。

 

工厂模式主要用于对功能相似的类进行抽象,抽象出的功能通过接口方式由实现类来实现,然后由工厂类装配不同的实现类,实现一个工厂生产不同产品的功能。

代码实现步骤:

(1)定义通知类接口

package 案例1;

//先定义一下通知接口
public interface INotice {

    //定义一个通知方法
    void sendMsg();

}

 

 

(2)定义EmailNotice类,实现NoticeInterface接口

 

 

 

package 案例1;

//定义一个右键通知类
public class EmailNotice implements INotice{

    //先定义几个字段
    private Teacher teacher;
    String message;

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public void sendMsg() {
         teacher.setClasstime(message + "邮件发送");
    }
}

 

(3)定义PhoneNotice类,实现NoticeInterface接口

package 案例1;

//电话通知类
public class PhoneNotice implements INotice{

    private Teacher teacher;
    String message;

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public void sendMsg() {

        teacher.setClasstime(message + "邮件发送");
    }
}

(4)定义NoticeFactory类,负责装配不同实现方式的通知类

 

 

package 案例1;

public class NoticeFactory {
    //通知工厂,夜光
    public static INotice getNotic(String noticeType){
        if (noticeType == null){
           return null;
        }
        if (noticeType.equalsIgnoreCase("email")){
           return new EmailNotice();
        }else if (noticeType.equalsIgnoreCase("phone")){
            return new PhoneNotice();
        }
        return null;
    }
}

 

 

 

 

 

 

 

 

3、项目的实体类——老师

项目的唯一实体类是老师类,实体类也是POJO类(简单的Java对象),实体类仅有属性以及获取和设置属性的get和set方法,没有事务处理方法,这是和Javabean不同的地方。

哪些类适合作为POJO类呢?项目中用于描述事物本身以及需要数据传递和序列化的类。

例如,项目中的数据库表、实体对象、序列化对象等。

 

在本项目案例中,老师类属于实体对象类。

package 案例1;

//实体类
public class Teacher {

    //定义两个字段
    private String name;
    private String classtime;

    //定义一个方法
    public String getNotify(){
        return name + "在" + classtime;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getClasstime() {
        return classtime;
    }

    public void setClasstime(String classtime) {
        this.classtime = classtime;
    }
}

4、项目的业务类——校长

业务类也称为BO(业务对象),用于处理项目中的业务逻辑。

 

业务逻辑主要用于项目涉及的各类业务操作。

例如,在本项目案例中,校长需要安排上课时间,并发送上课时间给老师。

 

在业务对象中,需要组织和协调实体类、组件类、DAO(数据访问对象)完成整个业务逻辑的处理操作。

 

其中,组件类是JavaBean,是用于处理具体事务的类。

 

例如,在本项目案例中,PhoneNotice、EmailNotice类就是组件类,用于处理发送通知事务。

 

 

package 案例1;

//定义校长类
public class Principal {
    //夜光:负责装配产品,关联老师类和通知类
    public String notifyTeacher(){
        StringBuilder notifyReturn = new StringBuilder();
        //夜光:获取邮件通知类,并且还需要强转一下
        EmailNotice emailNotice = (EmailNotice) NoticeFactory.getNotic("email");

        //夜光:获取电话通知类,并且还需要强转一下
        PhoneNotice phoneNotice = (PhoneNotice) NoticeFactory.getNotic("phone");

        //1. 发送通知给萧炎老师
        Teacher teacherXiao = new Teacher();
        teacherXiao.setName("萧炎");

        //2. 注入老师类到邮件通知类
        emailNotice.setTeacher(teacherXiao);
        //3. 注入消息到邮件通知类
        emailNotice.setMessage("8:00 大神java课程,异火编程");
        emailNotice.sendMsg(); //发送消息给萧老师
        notifyReturn.append(teacherXiao.getNotify() + "\n");


        //1. 发送通知给林动老师
        Teacher teacherLin = new Teacher();
        teacherLin.setName("林动");

        //2. 注入老师类到邮件通知类
        emailNotice.setTeacher(teacherLin);
        //3. 注入消息到邮件通知类
        emailNotice.setMessage("11:00 武祖C#课程,祖符编程");
        emailNotice.sendMsg(); //发送消息给萧老师
        notifyReturn.append(teacherLin.getNotify() + "\n");

        //1. 发送通知给唐三老师
        Teacher teacherTang = new Teacher();
        teacherTang.setName("唐三");

        //2. 注入老师类到邮件通知类
        phoneNotice.setTeacher(teacherTang);
        //3. 注入消息到邮件通知类
        phoneNotice.setMessage("18:00 海神python课程,唐门编程");
        phoneNotice.sendMsg(); //发送消息给萧老师
        notifyReturn.append(teacherTang.getNotify() + "\n");

        return notifyReturn.toString();

    }
}

 

5、项目技术架构存在的问题

 

项目技术架构主要由javaBean组件、业务逻辑处理、POJO(实体)、前端四部分组成。

JavaBean组件实现通知发送,应用工厂模式便于组件扩展。

 

业务逻辑处理部分调用NoticeFactory创建通知组件和Teacher类,并将Teacher类实例和消息注入到组件,最后调用组件发送消息。

 

从技术架构图可以看出,NoticeFactory(组件工厂)负责通知组件的创建,Principal(业务类)调用NoticeFactory获取组件,并将Teacher类实例和消息注入到组件。

 

Principal是主要控制类,控制了组件的创建和组件属性的注入。

 

Principal类对组件的较强控制,对程序的扩展性和易维护性显然是不利的。

 

例如,当程序需要增加微信通知方式,且老师都希望用微信通知时,麻烦就来了,需要修改大量程序代码。

 

再如,老师的上课时间可能每周或每天都有变化,把时间安排写在程序代码中显然是不妥的,应该写在程序外面,由外面对通知组件的属性进行注入。

要解决上面的问题,就需要弱化Principal类对组件的控制权,将组件的创建和属性的注入(图2红色点划线指示的功能)交给第三方托管,这个第三方就是Spring框架的IOC容器,控制反转就是将Principal类对组件的控制权移交给IOC容器。

 

 


6、Spring IOC容器的控制反转

 

Spring IOC容器是框架的核心,IOC是控制反转的意思,可以用来降低程序代码之间的耦合度。

 

把强耦合的代码依赖从代码中移出去,放到统一的XML配置文件中,将程序对组件的主要控制权交给IOC,由IOC统一加载和管理。

 

例如,可以把本案例中的JavaBean组件的创建、实体类的创建、以及JavaBean组件的属性注入等代码从Principal类移出,放入到Spring的XML配置文件中。

这样就实现了Principal类与JavaBean组件的代码解耦,也解决了项目案例技术架构所存在的问题。

 

package 案例1;

import org.springframework.context.ApplicationContext;

public class IOCPrincipal {

    //基于spring ioc 容器的校长类,从配置文件读取组件

    public String notifyTeacher(ApplicationContext ctx){

        StringBuilder notifyReturn = new StringBuilder();

        //从容器中读取萧炎老师的组件
        EmailNotice noticeXiao = ctx.getBean("emailNoticeXiao",EmailNotice.class);
        noticeXiao.sendMsg();
        //从容器中获取通知萧炎老师的实例
        Teacher teacherXiao = ctx.getBean("teacherXiao",Teacher.class);

        notifyReturn.append(teacherXiao.getNotify() + "<p>");

        //--------------------------------------------------------------------
        //从容器中读取萧炎老师的组件
        PhoneNotice noticeLin = ctx.getBean("phoneNoticeLin",PhoneNotice.class);
        noticeLin.sendMsg();
        //从容器中获取通知萧炎老师的实例
        Teacher teacherLin = ctx.getBean("teacherLin",Teacher.class);

        notifyReturn.append(teacherLin.getNotify() + "<p>");


        //--------------------------------------------------------------------
        //从容器中读取萧炎老师的组件
        PhoneNotice noticeTang = ctx.getBean("phoneNoticeTang",PhoneNotice.class);
        noticeTang.sendMsg();
        //从容器中获取通知萧炎老师的实例
        Teacher teacherTang = ctx.getBean("teacherTang",Teacher.class);

        notifyReturn.append(teacherTang.getNotify() + "<p>");


        return notifyReturn.toString();

    }


}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:http="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<!--    <bean id="audience"class="com.spring.test.aop.Audience"/>-->
        <bean id="teacherXiao" class="案例1.Teacher">
                <property name="name" value="萧炎"></property>
        </bean>
        <bean id="teacherLin" class="案例1.Teacher">
                <property name="name" value="林动"></property>
        </bean>
        <bean id="teacherTang" class="案例1.Teacher">
                <property name="name" value="唐三"></property>
        </bean>


        <bean id="emailNoticeXiao" class="案例1.EmailNotice">
                <property name="message" value="8:00 大神java课程,异火编程"></property>
        </bean>
        <bean id="phoneNoticeLin" class="案例1.PhoneNotice">
                <property name="message" value="11:00 武祖C#课程,祖符编程"></property>
        </bean>
        <bean id="phoneNoticeTang" class="案例1.PhoneNotice">
                <property name="message" value="18:00 海神python课程,唐门编程"></property>
        </bean>



</beans>

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值