版权声明:本文为 小异常 原创文章,非商用*转载-保持署名-注明出处,谢谢!
本文网址:/sun8112133/article/details/80058200
本篇主要对Spring框架中所涉及到的常见几种设计模式做简要总结(单例模式、工厂方法模式、抽象工厂模式、代理模式),其他不做过多的详细介绍。。
设计模式的原则:不改代码,只添代码。
Spring框架所涉及到的常见设计模式(三种创建型及一种结构型):
一、单例模式(创建型)
二、工厂方法模式(创建型)
三、抽象工厂模式(创建型)
四、代理模式(结构型)
一、单例模式(创建型)
1、什么是单例模式
单例对象在程序中有且只有一个实例。
2、单例模式的好处
1)节约内存,频繁创建对象,对系统内存也是一笔很大的开销;
2)省去 new操作符,降低了系统内存的使用频率,减轻GC压力;
3)对于比如像交易核心类,控制着整个交易流程,如果创建多个话,会使系统完全乱套。
3、单例模式的简单写法
1)懒汉模式:
public class Singleton {
private Singleton instance;
private Singleton() { }
public Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
2)饿汉模式:
public class Singleton {
private Singleton instance = new Singleton();
private Singleton() { }
public Singleton getInstance() {
return instance;
}
}
二、工厂方法模式
1、什么是工厂方法模式
建立一个工厂类,对实现了同一接口的产品类进行实例的创建。
2、工厂方法模式的好处
1)统一new对象,不在外面new对象,而在工厂(类)中new对象;
2)方便安全,将对象的创建与使用分开,隐藏了创建过程的复杂度。
3、工厂方法模式的缺点
类的创建依赖工厂类,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,工厂方法模式不利用扩展。
4、工厂方法模式的写法
1)简单工厂模式:
// 发送接口
public interface Sender {
public void send();
}
// 邮箱
public class Mail implements Sender {
@Override
public void send() {
("发送邮件!");
}
}
// 短信
public class Sms implements Sender {
@Override
public void send() {
("发送短信!");
}
}
// 创建具有发送功能的产品工厂类
public class SendFactory {
public Sender getSender(String type) {
if ("mail".equals(type)) {
return new Mail();
} else if ("sms".equals(type)) {
return new Sms();
} else {
("请输入正确的类型");
return null;
}
}
}
// 测试类
public class Test {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender mail = ("mail");
(); // 输出:发送邮件!
}
}
2)静态工厂模式(对工厂进行了改变):
// 创建具有发送功能的产品工厂类
public class SendFactory {
// 获取 邮箱 对象
public static Sender getMail() {
return new Mail();
}
// 获取 短信 对象
public static Sender getSms() {
return new Sms();
}
}
// 测试类
public class Test {
public static void main(String[] args) {
Sender mail = ();
(); // 输出:发送邮件!
}
}
三、抽象工厂模式
1、什么是抽象工厂模式
创建多个工厂类,一旦需要增加新的功能,直接增加新的工厂类就可以了。
2、抽象工厂模式的好处
如果你现在想增加一个功能,则只需做一个实现类实现XXX接口,同时做一个工厂类,实现工厂XXX接口,就OK了,无需去改动现成的代码。这样做,相比起工厂方法模式更利于扩展。
3、抽象工厂模式的写法
// 发送接口
public interface Sender {
public void send();
}
// 邮箱
public class Mail implements Sender {
@Override
public void send() {
("发送邮件!");
}
}
// 短信
public class Sms implements Sender {
@Override
public void send() {
("发送短信!");
}
}
// 新增加一个QQ
public class QQ implements Sender {
@Override
public void send() {
("发送QQ消息!");
}
}
// 创建一个专门用来生产“产品”的工厂类接口
public interface SenderFactory {
public static Sender getSender();
}
// 创建一个专门用来生产“邮箱产品”的工厂类
public class MailFactory implements SenderFactory {
@Override
public static Sender getSender() {
return new Mail();
}
}
// 创建一个专门用来生产“短信产品”的工厂类
public class SmsFactory implements SenderFactory {
@Override
public static Sender getSender() {
return new Sms();
}
}
// 新增加一个专门用来生产“QQ产生”的工厂类
public class QQFactory implements SenderFactory {
@Override
public static Sender getSender() {
return new QQ();
}
}
// 测试类
public class Test {
public static void main(String[] args) {
Sender QQ = ();
(); // 输出:发送QQ消息!
}
}
四、代理模式
1、什么是代理模式
代理模式就是代替原对象进行一系列的操作,比如我们去火车站买票,火车站代售处就可以代替火车站进行售票,但需要在原车票的费用上额外加一些手续费(以下是去火车站买票和去代售处买票的序列图)。
- 创建目标对象的类叫目标类或者被代理类(火车站);
- 创建代理对象的类加代理类(代售处)。
2、代理模式的好处
从以上序列图我们就可以看到代售处比火车站更加快捷方便,只需要交5元钱就可以节省大量的时间买到票。我们可以为“目标对象”提供一种“代理对象”以便于控制对目标对象的访问,也就是在“目标对象”的基础上添加一些功能。
3、代理模式的写法
1)静态代理模式:
// 买火车票接口
public interface TrainTicket {
// 买火车票
public void getTicket();
}
// 火车站
public class TrainStation implements TrainTicket {
// 买火车票
@Override
public void getTicket() {
("买火车票了!!");
}
}
// 火车票代售处
public class TrainProxy implements TrainTicket {
// 目标对象
private TrainTicket target;
public TrainProxy(TrainTicket target) {
this.target = target;
}
// 买火车票
@Override
public void getTicket() {
("收取手续费!");
();
}
}
// 测试类
public class Test {
public static void main(String[] args) {
// 目标对象(火车站,可以直接购买火车票)
TrainStation trainStation = new TrainStation();
// 代理对象(代售火车票)
TrainProxy trainProxy = new TrainProxy(trainStation);
();
}
}
2)JDK动态代理模式:
// 代售处的程序处理器
public class TicketProxy implements InvocationHandler {
// 目标对象
private Object target;
public TicketProxy(Object target) {
this.target = target;
}
/*
* 功能:对程序进行处理
* proxy: 代理对象
* method: 目标对象的反射对象的方法
* args: method方法的参数列表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
("收取手续费!!!");
(target, args); // 调用 target对象中的method方法
return null;
}
}
// 测试类
public class Test {
public static void main(String[] args) {
// 火车票
TrainTicket trainTicket = new TrainStation();
// 飞机票
PlaneTicket planeTicket = new Airport();
// 代售处(动态代理只需要一个代理对象就可以了)
// InvocationHandler handler = new TicketProxy(trainTicket);
// 代售火车票的程序处理器
// TrainTicket ticketProxy = (TrainTicket) (
// ().getClassLoader(),
// ().getInterfaces(), handler);
// ();
InvocationHandler handler = new TicketProxy(planeTicket);
// 代售飞机票的程序处理器
/*
* 功能:创建某类的代理对象
* newProxyInstance(loader, interfaces, handler)
* loader: 目标类的加载器
* interfaces: 目标类实现的所有接口反射对象
* handler: InvocationHandler 程序处理器
*/
// 创建代理对象(代售处)
PlaneTicket ticketProxy = (PlaneTicket) (
().getClassLoader(),
().getInterfaces(), handler);
();
}
}
3)CGlib动态代理模式:
// 火车站
public class TrainStation {
// 买火车票
public void getTicket() {
("买火车票了!!");
}
}
// 代售处的方法拦截器
public class TicketProxy implements MethodInterceptor {
// Enhancer允许为非接口类型创建一个Java代理。
// Enhancer动态创建了给定类型的子类但是拦截了所有的方法。
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class cls) {
// 设置要代理的目标类的class对象
(cls);
// 设置回调
(this);
return (); // 创建代理对象
}
/*
* 功能:通过继承的方式拦截父类(目标类)中所有方法
* obj: 目标对象
* method: 目标对象的方法
* args: method方法的参数列表
* proxy: 代理对象
*/
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
("收取手续费!!!");
// 代理对象调用父类(目标对象)的方法
(obj, args);
return null;
}
}
// 测试类
public class Test {
public static void main(String[] args) {
// 方法拦截器
TicketProxy proxy = new TicketProxy();
// 获取代理对象(代售处)
TrainStation trainStation = (TrainStation) ();
();
}
}
4、静态代理与动态代理的区别:
静态比较死,动态比较灵活。就比如代售处,如果用静态代理的话,如果需要代售火车票和代售飞机票,那就需要两个代理对象,这样很多代码重复性太高,也会造成代理类膨胀;如果用动态代理,只需要一个代理对象就可以,对不同的类不同的方法进行动态的代理,因为它说白了只是对买票进行代理。
5、CGlib动态代理与JDK动态代理的区别:
JDK动态代理只能代理实现了某些接口的目标类,如果这个目标类没有实现某些接口,是不能使用JDK动态代理的。
CGlib动态代理是针对类来实现代理,相当于对指定的目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用,但它不能对final修饰的类进行代理,因为final修饰的类不能被继承。