版权声明:本文为 小异常 原创文章,非商用自由转载-保持署名-注明出处,谢谢!
本文网址:https://blog.csdn.net/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 {@Overridepublic void send() {System.out.println("发送邮件!");}
}
// 短信
public class Sms implements Sender {@Overridepublic void send() {System.out.println("发送短信!");}
}
// 创建具有发送功能的产品工厂类
public class SendFactory {public Sender getSender(String type) {if ("mail".equals(type)) {return new Mail();} else if ("sms".equals(type)) {return new Sms();} else {System.err.println("请输入正确的类型");return null;}}
}
// 测试类
public class Test {public static void main(String[] args) {SendFactory factory = new SendFactory();Sender mail = factory.getSender("mail");mail.send();   // 输出:发送邮件!}
}
  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 = SendFactory.getMail();mail.send();   // 输出:发送邮件!}
}

三、抽象工厂模式

1、什么是抽象工厂模式

  创建多个工厂类,一旦需要增加新的功能,直接增加新的工厂类就可以了。

2、抽象工厂模式的好处

  如果你现在想增加一个功能,则只需做一个实现类实现XXX接口,同时做一个工厂类,实现工厂XXX接口,就OK了,无需去改动现成的代码。这样做,相比起工厂方法模式更利于扩展。

3、抽象工厂模式的写法

// 发送接口
public interface Sender {public void send();
}
// 邮箱
public class Mail implements Sender {@Overridepublic void send() {System.out.println("发送邮件!");}
}
// 短信
public class Sms implements Sender {@Overridepublic void send() {System.out.println("发送短信!");}
}
// 新增加一个QQ
public class QQ implements Sender {@Overridepublic void send() {System.out.println("发送QQ消息!");}
}// 创建一个专门用来生产“产品”的工厂类接口
public interface SenderFactory {public static Sender getSender();
}
// 创建一个专门用来生产“邮箱产品”的工厂类
public class MailFactory implements SenderFactory {@Overridepublic static Sender getSender() {return new Mail();}
}
// 创建一个专门用来生产“短信产品”的工厂类
public class SmsFactory implements SenderFactory {@Overridepublic static Sender getSender() {return new Sms();}
}
// 新增加一个专门用来生产“QQ产生”的工厂类
public class QQFactory implements SenderFactory {@Overridepublic static Sender getSender() {return new QQ();}
}// 测试类
public class Test {public static void main(String[] args) {Sender QQ = QQFactory.getSender();QQ.send();   // 输出:发送QQ消息!}
}

四、代理模式

1、什么是代理模式

  代理模式就是代替原对象进行一系列的操作,比如我们去火车站买票,火车站代售处就可以代替火车站进行售票,但需要在原车票的费用上额外加一些手续费(以下是去火车站买票和去代售处买票的序列图)。

  • 创建目标对象的类叫目标类或者被代理类(火车站);
  • 创建代理对象的类加代理类(代售处)。
Created with Raphaël 2.1.0家家火车站火车站火车票火车票去火车站从家走需要2个小时才可以到达火车站,太不方便了!!买票需要支持20元
Created with Raphaël 2.1.0家家代售处代售处火车票火车票去代售处从家走10分钟就可以到达代售处!买票需要支持25元(5元手续费)

2、代理模式的好处

  从以上序列图我们就可以看到代售处比火车站更加快捷方便,只需要交5元钱就可以节省大量的时间买到票。我们可以为“目标对象”提供一种“代理对象”以便于控制对目标对象的访问,也就是在“目标对象”的基础上添加一些功能。

3、代理模式的写法

  1)静态代理模式:
// 买火车票接口
public interface TrainTicket {// 买火车票public void getTicket();
}
// 火车站
public class TrainStation implements TrainTicket {// 买火车票@Overridepublic void getTicket() {System.out.println("买火车票了!!");}
}
// 火车票代售处
public class TrainProxy implements TrainTicket {// 目标对象private TrainTicket target;public TrainProxy(TrainTicket target) {this.target = target;}// 买火车票@Overridepublic void getTicket() {System.out.println("收取手续费!");target.getTicket();}
}
// 测试类
public class Test {public static void main(String[] args) {// 目标对象(火车站,可以直接购买火车票)TrainStation trainStation = new TrainStation();// 代理对象(代售火车票)TrainProxy trainProxy = new TrainProxy(trainStation);trainProxy.getTicket();}
}
  2)JDK动态代理模式:
// 代售处的程序处理器
public class TicketProxy implements InvocationHandler {// 目标对象private Object target;public TicketProxy(Object target) {this.target = target;}/** 功能:对程序进行处理* proxy: 代理对象* method: 目标对象的反射对象的方法* args: method方法的参数列表*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("收取手续费!!!");method.invoke(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) Proxy.newProxyInstance(
//              trainTicket.getClass().getClassLoader(),
//              trainTicket.getClass().getInterfaces(), handler);
//      ticketProxy.getTicket();InvocationHandler handler = new TicketProxy(planeTicket);  // 代售飞机票的程序处理器/** 功能:创建某类的代理对象* newProxyInstance(loader, interfaces, handler)* loader: 目标类的加载器* interfaces: 目标类实现的所有接口反射对象* handler: InvocationHandler 程序处理器*/// 创建代理对象(代售处)PlaneTicket ticketProxy = (PlaneTicket) Proxy.newProxyInstance(planeTicket.getClass().getClassLoader(),planeTicket.getClass().getInterfaces(), handler);ticketProxy.getTicket();}
}
  3)CGlib动态代理模式:
// 火车站
public class TrainStation {// 买火车票public void getTicket() {System.out.println("买火车票了!!");}
}
// 代售处的方法拦截器
public class TicketProxy implements MethodInterceptor {// Enhancer允许为非接口类型创建一个Java代理。// Enhancer动态创建了给定类型的子类但是拦截了所有的方法。private Enhancer enhancer = new Enhancer();public Object getProxy(Class cls) {// 设置要代理的目标类的class对象 enhancer.setSuperclass(cls);// 设置回调  enhancer.setCallback(this);return enhancer.create();   // 创建代理对象}/** 功能:通过继承的方式拦截父类(目标类)中所有方法* obj: 目标对象* method: 目标对象的方法* args: method方法的参数列表* proxy: 代理对象*/@Overridepublic Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {System.out.println("收取手续费!!!");// 代理对象调用父类(目标对象)的方法proxy.invokeSuper(obj, args);return null;}
}
// 测试类
public class Test {public static void main(String[] args) {// 方法拦截器TicketProxy proxy = new TicketProxy();// 获取代理对象(代售处)TrainStation trainStation = (TrainStation) proxy.getProxy(TrainStation.class);trainStation.getTicket();}
}

4、静态代理与动态代理的区别:

  静态比较死,动态比较灵活。就比如代售处,如果用静态代理的话,如果需要代售火车票和代售飞机票,那就需要两个代理对象,这样很多代码重复性太高,也会造成代理类膨胀;如果用动态代理,只需要一个代理对象就可以,对不同的类不同的方法进行动态的代理,因为它说白了只是对买票进行代理。

5、CGlib动态代理与JDK动态代理的区别:

  JDK动态代理只能代理实现了某些接口的目标类,如果这个目标类没有实现某些接口,是不能使用JDK动态代理的。

  CGlib动态代理是针对类来实现代理,相当于对指定的目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用,但它不能对final修饰的类进行代理,因为final修饰的类不能被继承。

单例工厂代理模式总结相关推荐

  1. spring中的单例工厂SingletonBeanRegistry设计与实现

    单例工厂接口为SingletonBeanRegistry,主要是单例的注册,其默认实现为DefaultSingletonBeanRegistry 1.类层次图 2.单例工厂在循环依赖时的流程

  2. 高仿真的类-单例工厂的顶层设计

    /*** 单例工厂的顶层设计*/ public interface V1BeanFactory {/*** 根据beanName从IOC容器中获得一个实例Bean* @param beanName* ...

  3. Redis 单例、主从模式、sentinel 以及集群的配置方式及优缺点对比(转)

    摘要: redis作为一种NoSql数据库,其提供了一种高效的缓存方案,本文则主要对其单例,主从模式,sentinel以及集群的配置方式进行说明,对比其优缺点,阐述redis作为一种缓存框架的高可用性 ...

  4. Redis 单例、主从模式、sentinel 以及集群的配置方式及优缺点对比

    点击关注公众号,利用碎片时间学习 来源:blog.csdn.net/xsxy0506/article/details/117321181 redis作为一种NoSql数据库,其提供了一种高效的缓存方案 ...

  5. IoC与DI工厂、单例、原型模式详解

    1.工厂模式 1.1 工厂模式的由来 在现实生活中我们都知道 原始社会自给自足(没有工厂) 农耕社会有了小作坊(简单工厂,如民间酒坊) 工业革命后有了流水线(工厂方法,自产自销) 现代产业链中有代工厂 ...

  6. 【设计模式】创建者模式(单例工厂原型建造者)

    文章目录 1.单例设计模式 1.1 单例模式概述 1.2 单例模式的实现 1.2.1 饿汉式(静态变量方式) 1.2.2 饿汉式(静态代码块方式) 1.2.3 懒汉式(线程不安全) 1.2.4 懒汉式 ...

  7. javascript单例、代理、状态设计模式

    一.创建型设计模式(三大类设计模式) 创建型设计模式 --"创建"说明该类别里面的设计模式就是用来创建对象的,也就是在不同的场景下我们应该选用什么样的方式来创建对象. 1. 单例模 ...

  8. PHP设计模式 二 (单例 工厂 注册)

    单例模式 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源. ...

  9. Redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:爱宝贝丶 my.oschina.net/zhangxufen ...

最新文章

  1. 【物联网智能网关-02】获取摄像头数据+显示
  2. python爬虫入门代码-Python爬虫入门
  3. mybatis使用foreach实现sql的in查询
  4. HP officejet、PageWide打印机任意代码执行漏洞cve-2017-2741 Tenable发布漏洞检测插件...
  5. cacti linux 模板,Cacti模板
  6. 深度学习之基于AlexNet实现猫狗大战
  7. 打印狗的健康值Java_嵌入式狗的JAVA之路 HTML 补课
  8. centos7 mysql创建表_centos7下创建数据库和用户
  9. python 运行时 变量_在运行时在python中检索变量的名称?
  10. 【论文复现】ReLU、Leaky ReLU、PReLU、RReLU实验对比(2015)
  11. FreeImage的学习总结总结(四)
  12. 对无序的边界点排序(顺时针绘制边界)
  13. 如何防止别人偷窥我给宝贝儿娜娜的信
  14. 瑞云Rayvision渲染的原创动画《吃饭睡觉打豆豆》震撼来袭 ——创造产业历史,日点击量过200万次...
  15. Mac Mounty正常卸载方法(mount failed异常解决)
  16. Linux远程管理常用命令(超全超详细)【持续更新】
  17. 《用图表说话》读后感
  18. 顺序表的具体使用方法.数据解构(二)
  19. 视觉传导通路,光能转化为神经电能后,神经电冲动如何传导?|小白心理-312/347考研答疑
  20. Java 网络编程之swing图形化QQ聊天室

热门文章

  1. 音乐迷福利【listen1】【搜你妹】
  2. HTML5开发基础培训(包含jquery、css、javascript、bootstrap)
  3. python接口学习记录
  4. Oracle Secure Global Desktop 部署考虑事项
  5. linux系统中程序调试指令(gdb)
  6. 计算机通信电气电子适合女生学,工科中适合女生的专业和不适合女生的专业有哪些...
  7. aapt 命令生成 R文件
  8. C#与三菱PLC MC协议通信,Java与三菱PLC MC协议通信
  9. 北京提取公积金将无需购房合同 租房可3月提1次
  10. php502bad gateway,PHP表单提交后出现502 bad gateway解决办法