深入理解Spring(七)、Spring常用设计模式
前言
深入理解Spring源码分为7小节,本小节为Spring源码第7小节,各个小节目录如下。
-
扫描过程 -
bean创建过程 -
容器扩展 -
AOP源码分析 -
事务源码分析 -
Spring JDBC源码分析
7. Spring常用设计模式
优秀的框架多多少少都会用到一些设计模式,Spring也不例外,但是这些模式可能你看多少遍都不明白,为什么这样写,这不是多此一举吗,设计模式需要写大量代码,才能从中间悟出来他的真谛。
下面来介绍Spring常用的几种。
工厂模式
工厂模式用来创建对象,使用频率比较高,下面举例。
现在有很多不同品牌的电脑,如ThinkPad、Mac,他们我们把他们的厂商抽象成工厂,每个工厂可以生产不同电脑,定义如下。
public abstract class AbstractComputerFactory {
public abstract <T extends AbstractComputer> AbstractComputer createComputer(Class<T> computerClass);
}
public abstract class AbstractComputer {
public abstract void start();
public abstract void shutdown();
}
工厂实现类。
public class ComputerFactory extends AbstractComputerFactory {
@Override
public <T extends AbstractComputer> AbstractComputer createComputer(Class<T> computerClass) {
try {
return computerClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
public class Main {
static class ThinkPadComputer extends AbstractComputer{
@Override
public void start() {
}
@Override
public void shutdown() {
}
}
static class MacComputer extends AbstractComputer{
@Override
public void start() {
System.out.println("mac start");
}
@Override
public void shutdown() {
System.out.println("mac shutdown");
}
}
public static void main(String[] args) {
AbstractComputer computer = new ComputerFactory().createComputer(MacComputer.class);
computer.start();
}
}
上面我们称为简单工厂,还可以上升到另一个层面,叫抽象工厂。联想现实中的工厂都是具体的,也就是每个工厂都会生产某一中具体的产品,那么抽象工厂意味着生产出来的产品不是确定的。
抽象工厂的定义是为一组相关的对象提供一个接口。
还拿上面制作电脑的来说,每种工厂创建的产品内部零件可能都不一样,比如ThinkPad X1隐士使用的CPU是Intel Core i9,屏幕尺寸是16,而ThinkPad X13的CPU是Intel Core i5,屏幕尺寸是13,我们为这个进行工厂抽象。
public abstract class ICpu {
public abstract void createCpu();
}
public abstract class IScreen {
public abstract void createScreen();
}
不同的产品实现类。
public class Screen13 extends IScreen {
@Override
public void createScreen() {
System.out.println("屏幕13");
}
}
public class Screen16 extends IScreen {
@Override
public void createScreen() {
System.out.println("屏幕16");
}
}
public class IntelI5 extends ICpu {
@Override
public void createCpu() {
System.out.println("Intel i5");
}
}
public class IntelI9 extends ICpu {
@Override
public void createCpu() {
System.out.println("Intel i9");
}
}
抽象工厂
public abstract class ThinkPadFactory {
public abstract ICpu createCpu();
public abstract IScreen createScreen();
}
ThinkPad x1的实现。
public class ThinkPadX1Factory extends ThinkPadFactory {
@Override
public ICpu createCpu() {
return new IntelI9();
}
@Override
public IScreen createScreen() {
return new Screen16();
}
}
ThinkPad x13的实现。
public class ThinkPadX13Factory extends ThinkPadFactory {
@Override
public ICpu createCpu() {
return new IntelI5();
}
@Override
public IScreen createScreen() {
return new Screen13();
}
}
public class Main {
public static void main(String[] args) {
ThinkPadX1Factory thinkPadX1Factory = new ThinkPadX1Factory();
thinkPadX1Factory.createCpu().createCpu();
ThinkPadX13Factory thinkPadX13Factory = new ThinkPadX13Factory();
thinkPadX13Factory.createCpu().createCpu();
}
}
Spring中很多Factory,核心BeanFactory就是一个。
原型模式
原型模式的核心是一个clone方法,可以通过这个方法进行对象拷贝,拷贝的对象和原来对象是不同的,但是里面字段值是一样的,网上可能有这样一个面试提,new和clone那个快?这其实不一定谁快谁慢,还是看场合,比如在构造方法执行了一些耗时的事情,那么clone会比较快,因为clone不会重新执行构造方法。
如下,被clone的对象必须实现Cloneable。
Email email = new Email("1111@qq.com", "数据i");
Email clone = email.clone();
clone.setContent("数据2");
System.out.println(email.equals(clone));
public class Email implements Cloneable {
private String sender;
private String content;
@Override
public Email clone() {
try {
Email clone = (Email) super.clone();
return clone;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
public Email(String sender, String content) {
this.sender = sender;
this.content = content;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
代理模式
代理是个很常用的模式,举个例子,对象A是老大,你想要和老大沟通,但必须和老大的跟班先请示,跟班可能会拒绝掉一些无用信息。
public abstract class Subject {
public abstract void visit();
}
public class RealSubject extends Subject{
@Override
public void visit() {
System.out.println("原方法");
}
}
public class ProxySubject extends Subject{
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void visit() {
if (LocalDateTime.now().getHour()>23){
return;
}
realSubject.visit();
}
}
ProxySubject proxySubject = new ProxySubject(new RealSubject());
proxySubject.visit();
上面所示的静态代理,还有动态代理,比如使用Proxy、CGLIB这种方法,Spring的AOP就是使用动态代理。
策略模式
每个问题都有不同的解决方法,或者每个时机都有不同的方法,策略模式就是解决这个问题,比如女朋友特别爱打我,可气的还是她会分不同时间打,早上一把打2次,中午打3次,晚上打的就更多了,10次。我们把这个打抽象为接口。
public interface Hit {
public void start();
}
女朋友
public class Girl {
private Hit hit;
public void setHit(Hit hit) {
this.hit = hit;
}
public void start() {
hit.start();
}
}
public class Main {
static class MorningHit implements Hit {
@Override
public void start() {
for (int i = 0; i < 2; i++) {
System.out.println("打我");
}
}
}
static class NoonHit implements Hit {
@Override
public void start() {
for (int i = 0; i < 3; i++) {
System.out.println("打我");
}
}
}
static class NightHit implements Hit {
@Override
public void start() {
for (int i = 0; i < 10; i++) {
System.out.println("打我");
}
}
}
public static void main(String[] args) {
Girl girl = new Girl();
girl.setHit(new NightHit());
girl.start();
}
}
模板模式
每个问题可能都有一套固定的模板解决,同样是女朋友打我,总会先捋起袖子、然后上手,但是在超级生气的时候,不会上手,而是上脚。
public abstract class Hit {
public void 捋起袖子() {
System.out.println("捋起袖子");
}
public void 开打() {
System.out.println("上手");
}
public void begin() {
捋起袖子();
开打();
}
}
public class Girl {
private Hit hit;
public void setHit(Hit hit) {
this.hit = hit;
}
public void begin() {
hit.begin();
}
}
public class Main {
static class BaseHit extends Hit{}
static class SeriousHit extends Hit{
@Override
public void 开打() {
System.out.println("上脚");
}
}
public static void main(String[] args) {
Girl girl = new Girl();
girl.setHit(new BaseHit());
girl.begin();
girl.setHit(new SeriousHit());
girl.begin();
}
}
输出如下。
捋起袖子
上手
捋起袖子
上脚
- END -
原文始发于微信公众号(十四个字节):深入理解Spring(七)、Spring常用设计模式