Spring架构与设计学习笔记(一)之初步了解Spring架构

目录

一、Spring简介

1.1初步了解Spring架构

1.2初步了解Spring设计模式

1.3初步了解Spring软件架构设计原则

1.3.1开闭原则

1.3.2依赖倒置原则

1.3.3单一职责原则

1.3.4接口隔离原则

1.3.5迪米特原则

1.3.6里氏替换原则

1.3.7合成复用原则

1.4反射机制


一、Spring简介

Spring是一个开源免费框架,根本使命:“简化企业级应用开发”(全方位地简化了Java开发)

特点:

①轻量级(零配置编程、API使用简单)

②最小侵入性

③引入Spring时,原有代码或设计能够尽可能地少修改。

④面向Bean编程BOP(Bean在Spring中是真正的主角)

⑤控制反转IoC、依赖注入DI

⑥Spring通过IoC容器,来管理bean对象之间的依赖关系

⑦DI是IoC的一种实现方式

⑧面向切面编程AOP

⑨对事务支持

⑩兼容各类主流框架

1.1初步了解Spring架构

1、Beans和Core模块是Spring的核心模块,包含了控制反转(IoC)和依赖注入(DI)。

2、Context模块扩展了BeanFactory(Spring的最高级抽象),为其添加Bean生命周期等功能。

3、AOP模块是Spring的另一个核心模块,是AOP主要的实现模块(AOP底层为动态代理模式)。 4、Aspects模块为Spring提供多种AOP实现方法。

5、Transactions是事务控制实现模块,为事务做了很好的封装。

6、JDBC模块用于简化SpringJDBC操作,提供了JdbcTemplate等类。

7、ORM模块是ORM(对象关系映射)框架支持模块,可集成Hibernate等框架。

8、WebMVC模块实现了SpringMVC的Web应用。

1.2初步了解Spring设计模式

设计模式(Design Pattern)共23种,是前辈们对代码开发经验的总结,是解决特定问题的一系列套路,它不是语法规定,而是一套用来提高代码的可复用性、可维护性、可读性、稳健性以及安全性的解决方案。

本质是对面向对象设计原则的实际应用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。

1.3初步了解Spring软件架构设计原则

1.3.1开闭原则

开闭原则(Open-Closed Principle,OCP)是指一个软件实体(如类、模块和函数)应该对扩展开放,对修改关闭。 强调用抽象构建框架,用实现扩展细节,可以提高软件系统的可复用性及可维护性。 是面向对象设计中最基础的设计原则。 例如版本更新,我们尽可能不修改源代码,但是可以增加新功能。

下面以“课程体系”为例来进行说明:

1、首先现在有一个课程接口ICourse

public interface ICourse {
    Integer getId();
    String getName();
    Double  getPrince();
}

2、整个课程生态中有Java架构、大数据、人工智能等,现在有一个Java架构课程的类

public class JavaCourse implements ICourse {
    private Integer Id;
    private String name;
    private Double price;

    public JavaCourse(Integer id , String name , Double price ){
        Id = id;
        this.name = name;
        this.price = price;
    }
    @Override
    public Integer getId() {
        return Id;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Double getPrince() {
        return price;
    }
}

3、我们再写一个处理优惠逻辑的类JavaDiscountCourse:

public class JavaDiscountCourse extends JavaCourse {
    public JavaDiscountCourse(Integer id, String name, Double price) {
        super(id, name, price);
    }
    public Double getOriginPrice(){
        return super.getPrince();
    }
    public Double getPrince() {
        return super.getPrince()*0.6;
    }

}

4、测试类

public class OpenCloseTest {
    public static void main(String[] args){
        ICourse javaCourse;
        javaCourse = new JavaDiscountCourse(1,"裤子",120.0);
        System.out.println(javaCourse.getPrince());
    }
}

1.3.2依赖倒置原则

依赖倒置原则(Dependence Inversion Principle,DIP)是指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。 抽象不应该依赖细节,细节应该依赖抽象。 可以减少类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,降低修改程序造成的风险。

还是以“课程”为例来进行说明:

1.创建课程的抽象ICourse接口

public interface ICourse {
    void study();
}

2.编写JavaCourse、PythonCourse等实现类

public class JavaCourse implements ICourse{
    @Override
    public void study() {
        System.out.println("Tom正在学习Java课程");
    }
}
public class PythonCourse implements ICourse {
    @Override
    public void study() {
        System.out.println("Tom正在学习Python课程");
    }
}

3.编写Tom类并进行调用

public class Tom {
    public void study(ICourse iCourse){
        iCourse.study();
    }
}

4.测试类

public class DIPtest {
    public static void main(String[] args){
        Tom tom = new Tom();
        tom.study(new JavaCourse());
        tom.study(new PythonCourse());
    }
}

1.3.3单一职责原则

单一职责原则(Simple Responsibility Principle,SRP)是指不要存在多于一个导致类变更的原因。 假设有一个类负责两个职责,一旦发生需求变更,修改其中一个职责的代码,有可能导致另一个职责的功能发生故障。 总体来说,就是一个类、接口或方法只负责一项职责。

还是以“课程”为例来进行说明:

1、若我们有直播课和录播课,直播课不能快进退,而录播课可以,两者功能职责不一样。

2、按照传统方式来编写,即创建一个Course类如下

public class Course {
    public void study(String courseName){
        if("直播课".equals(courseName)){
            System.out.println(courseName +"不能快进");
        }else {
            System.out.println(courseName +"可以快进");
        }
    }
}

(如果要再加一种类型的课(比如VIP课可以下载),那这种方式要怎么修改?)

↓↓↓

刚才方式,若要“VIP课程可以下载”,必须修改代码,而修改代码势必会影响到其他职责,容易带来不可控的风险。 因此我们可以对刚才的代码进行解耦和优化:

public class LiveCourse {
    public void study(String courseName){
        System.out.println(courseName +"不能快进");
    }
}
public class ReplayCourse {
    public void study(String courseName){
        System.out.println(courseName +"可以快进");
    }
}

3.测试类

public class SRPTest {
    public static void main(String[] args){
        LiveCourse liveCourse = new LiveCourse();
        liveCourse.study("直播课");

        ReplayCourse replayCourse = new ReplayCourse();
        replayCourse.study("录播课");
    }
}

1.3.4接口隔离原则

接口隔离原则(Interface Segregation Principle,ISP)是指用多个专门的接口,而不是用单一的总接口,客户端不应该依赖它不需要的接口。 一个类对另一个类的依赖应该建立在最小的接口之上。 建立单一接口,不要建立庞大臃肿的接口。 尽量细化接口,接口中的方法尽量少(不是越少越好,要适度)

高内聚低耦合思想,使类有很好的可读性、可扩展性和可维护性

下面以“动物行为”举例:

1.将动物行为的接口分解(分解为多个小接口)

public interface IEatAnimal {
    void eat();
}
public interface IFlyAnimal {
    void fly();
}
public interface ISwimAnimal {
    void swim();
}

2.Dog的动物行为只实现IEatAnimal和ISwimAnimal接口

public class Dog implements IEatAnimal,ISwimAnimal{
    @Override
    public void eat() {
        System.out.println("狗可以吃饭");
    }
    @Override
    public void swim() {
        System.out.println("狗可以游泳");
    }
}

1.3.5迪米特原则

迪米特原则(Law of Demeter,LoD)是指一个对象应该对其他对象保持最少的了解。 又叫最少知道原则(Least Knowledge Principle,LKP),尽量降低类与类之间的耦合度。 迪米特原则主要强调:只和朋友交流,不和陌生人说话。 出现在成员变量、方法的输入输出参数中的类称为朋友类。 出现在方法体内部的类不属于朋友类。

下面以“权限系统”举例:

若Boss要查看发布到线上的课程数量,需要找TeamLeader去统计,TeamLeader再把统计结果告诉Boss。

1、不遵循此原则的情况

这种方式,代码运行没有问题。 但根据迪米特原则,Boss只想要结果,跟Course不是“朋友”,不应该直接进行交流 

优化:(把Boss与Course之间的直接依赖关系去掉)

1.3.6里氏替换原则

举例:

1、假设有个接口IDog,有MyDog类实现了它。

2、父类ParentClass如下:

 

1.3.7合成复用原则

合成复用原则(Composite/Aggregate Reuse Principle,CARP)是指尽量使用对象组合(has-a)/聚合(contains-a)而不是继承关系达到软件复用的目的。

组合:父类拥有子类,子类不能独立于父类存在。

聚合:父类包含子类,子类可以独立于父类存在。

可使系统更加灵活,降低类与类之间的耦合度,修改一个类对其他类的影响也较少。

1、继承叫做白箱复用,相当于把所有的实现细节暴露给子类。

2、组合/聚合称为黑箱复用,无法获取类之外的对象的实现细节

下面以“数据库操作”为例来进行说明:

1、先来创建DBConnection类:

2、创建ProductDao类:

1.4反射机制

Reflection(反射)允许程序在执行期取得类的任何内部信息(如:类名、接口、方法、属性等),并能直接操作任意对象的内部属性及方法(包括private修饰的)。

加载完类后,就会在堆方法区中产生一个Class对象(单例的),这个对象包含完整的类的结构信息。我们可以透过这个Class对象看到类的结构,所以我们称之为:反射。 反射获取类的对应Class对象(几种方法之一):     Class c = Class.forName(“java.lang.String”)

反射的优缺点:

优点:可以动态创建对象和编译,体现很大的灵活性。

缺点:对性能有所影响,慢于直接执行相同的操作 

Person person = new Student();

//方式一:通过对象获得

Class c1 = person.getClass();

//方式二:通过forName获得

Class c2 = Class.forName(“com.Student”);

//方式三:通过类名.class获得

Class c3 = Student.class;

//这三个对象的hashCode一致,因此这三者为同一对象

 4.4 获取类的运行时结构

ღ感谢您的阅读ღ

如有不好的地方还请大佬们多多指教

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

elmM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值