java基础 day-17 设计模式(单例,工厂,代理),静态动态代理,数据库连接池(动态代理)
设计模式:是一种思维方式,组织类的方式。
- 单例模式:Singleton模式。指一个类,仅能创建唯一实例。
- 实现
- 使用类变量,提前创建类的实例,饿汉式-不管用不用到,都会在内存中占据空间。线程安全的。
一上来我就把对象给new好了,来了可以直接“吃” 了
package javaPro1;public class Single {//1、私有化构造函数private Single() {}// 2、new一个Single对象private static final Single SINGLE = new Single();// 3、创建一个方法,让外面的类可以拿到对象的引用public static Single getInstance() {return SINGLE;}
}
package javaPro1;public class Single {//线程安全的private Single() {} public static Single getInstance() {return SingleHolder.SINGLE;}private static class SingleHolder{private static final Single SINGLE = new Single();}}
- 懒汉式:不会在内存中创建空间,返回唯一变量时,才进行创建。非线程安全的。
(要是有人问单例的延迟加载方式值得就是这种方式)一开始我不给你new对象,你来找我,我再给你new对象。
package javaPro1;public class Single {//1、私有化构造函数private Single() {}// 2、声明一个对象的引用private static Single SINGLE;// 3、判断一下,如果对象为null,创建对象public static Single getInstance() {if(SINGLE == null) {SINGLE = new Single();}return SINGLE;}
}
- 懒汉式,保证线程安全-双检锁
package javaPro1;public class Single {//1、私有化构造函数private Single() {}// 2、声明一个对象的引用private volatile static Single SINGLE;// 3、判断一下,如果对象为null,创建对象public static Single getInstance() {//保证线程安全if(SINGLE == null) {synchronized (SINGLE) {//双检锁if(SINGLE == null) {SINGLE = new Single();}} }return SINGLE;}
}
- 测试类
package javaPro1;public class Test1 {public static void main(String[] args) {Single m1 = Single.getInstance();Single m2 = Single.getInstance();System.out.println(m1 == m2);//true}
}
以下内容参考自菜鸟教程
- 工厂模式:创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
- 意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
- 主要解决:主要解决接口选择的问题。
- 何时使用:我们明确地计划不同条件下创建不同实例时。
- 如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。
- 关键代码:创建过程在其子类执行
- 实现
- 步骤 1、创建一个接口:
public interface Shape {void draw();
}
- 步骤 2、创建实现接口的实体类。
public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Inside Rectangle::draw() method.");}
}
public class Square implements Shape {@Overridepublic void draw() {System.out.println("Inside Square::draw() method.");}
}
public class Circle implements Shape {@Overridepublic void draw() {System.out.println("Inside Circle::draw() method.");}
}
- 步骤3、创建一个工厂,生成基于给定信息的实体类的对象。
public class ShapeFactory {//使用 getShape 方法获取形状类型的对象public Shape getShape(String shapeType){if(shapeType == null){return null;} if(shapeType.equalsIgnoreCase("CIRCLE")){return new Circle();} else if(shapeType.equalsIgnoreCase("RECTANGLE")){return new Rectangle();} else if(shapeType.equalsIgnoreCase("SQUARE")){return new Square();}return null;}
}
- 步骤4、使用该工厂,通过传递类型信息来获取实体类的对象。
public class FactoryPatternDemo {public static void main(String[] args) {ShapeFactory shapeFactory = new ShapeFactory();//获取 Circle 的对象,并调用它的 draw 方法Shape shape1 = shapeFactory.getShape("CIRCLE");//调用 Circle 的 draw 方法shape1.draw();//获取 Rectangle 的对象,并调用它的 draw 方法Shape shape2 = shapeFactory.getShape("RECTANGLE");//调用 Rectangle 的 draw 方法shape2.draw();//获取 Square 的对象,并调用它的 draw 方法Shape shape3 = shapeFactory.getShape("SQUARE");//调用 Square 的 draw 方法shape3.draw();}
}
- 步骤5、执行程序,输出结果:
- 代理模式:在代理模式(Proxy Pattern)中,某个类代理另-一个类的全部或部分操作,代理的过程中,有可能对目标类的职责进行功能的改变,校验,或增强。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
- 意图:为其他对象提供一种代理以控制对这个对象的访问。
- 主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
- 何时使用:想在访问一个类时做一些控制。
- 如何解决:增加中间层。
- 关键代码:实现与被代理类组合。
- 应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。
- 实现
- 步骤1、创建一个接口
public interface Image {void display();
}
- 步骤2、创建实现接口的实体类。
public class RealImage implements Image {private String fileName;public RealImage(String fileName){this.fileName = fileName;loadFromDisk(fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}private void loadFromDisk(String fileName){System.out.println("Loading " + fileName);}
- 步骤3、当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。
public class ProxyPatternDemo {public static void main(String[] args) {Image image = new ProxyImage("test_10mb.jpg");// 图像将从磁盘加载image.display(); System.out.println("");// 图像不需要从磁盘加载image.display(); }
}
- 步骤4、执行程序,输出结果
静态代理
以下内容参考自博客园周有才
- 代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。
- 示例:我们平常去电影院看电影的时候,在电影开始的阶段是不是经常会放广告呢?电影是电影公司委托给影院进行播放的,但是影院可以在播放电影的时候,产生一些自己的经济收益,比如卖爆米花、可乐等,然后在影片开始结束时播放一些广告。
- 现在用代码来进行模拟。
- 首先得有一个接口,通用的接口是代理模式实现的基础。这个接口我们命名为 Movie,代表电影播放的能力。
package com.pro2;public interface Movie {void play();
}
- 然后,我们要有一个真正的实现这个 Movie 接口的类,和一个只是实现接口的代理类。这个表示真正的影片。它实现了 Movie 接口,play() 方法调用时,影片就开始播放。那么 Proxy 代理呢?
package com.pro2;public class RealMovie implements Movie {@Overridepublic void play() {System.out.println("您正在观看的电影为:肖申克的救赎!");}}
- Cinema 就是 Proxy 代理对象,它有一个 play() 方法。不过调用 play() 方法时,它进行了一些相关利益的处理,那就是广告。现在,我们编写测试代码。
package com.pro2;public class Cinema implements Movie {RealMovie realMovie;public Cinema(RealMovie realMovie) {super();this.realMovie = realMovie;}@Overridepublic void play() {guanggao(true);realMovie.play();guanggao(false);}public void guanggao(boolean isStart) {if (isStart) {System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!");} else {System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!");}}}
- 测试代码
package com.pro2;public class ProxyTest {public static void main(String[] args) {RealMovie realmovie = new RealMovie();Movie movie = new Cinema(realmovie);movie.play();}
}
- 输出结果:
动态代理
- 既然是代理,那么它与静态代理的功能与目的是没有区别的,唯一有区别的就是动态与静态的差别。
- 那么在动态代理的中这个动态体现在什么地方?
上一节代码中 Cinema 类是代理,我们需要手动编写代码让 Cinema 实现 Movie 接口,而在动态代理中,我们可以让程序在运行的时候自动在内存中创建一个实现 Movie 接口的代理,而不需要去定义 Cinema 这个类。这就是它被称为动态的原因。- 示例:假设有一个大商场,商场有很多的柜台,有一个柜台卖茅台酒。我们进行代码的模拟。
- 卖酒的一个接口
package com.pro3;public interface SellWine {void sellwine();}
- 实现接口,卖茅台酒
package com.pro3;public class MaotaiJiu implements SellWine{public void sellwine() {System.out.println("我卖的是茅台酒!");}}
- 代理可对其内容做修改和补充
package com.pro3;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class Test {public static void main(String[] args) {SellWine a1 = new MaotaiJiu();// 可以创建动态代理SellWine a2 = (SellWine)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class<?>[] {SellWine.class}, new InvocationHandler() {// 拦截所代理的类的行为@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("动态代理可添加,在卖酒动作前");// a1.sellwine();method.invoke(a1, args);System.out.println("动态代理可添加,在卖酒动作后");return null;}});a2.sellwine();}}
- 语法
- Proxy
/*
loader 自然是类加载器,一般写作:Thread.currentThread().getContextClassLoader()
interfaces 代码要用来代理的接口
h 一个 InvocationHandler 对象
*/
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
- InvocationHandler类
InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。
public interface InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
- invoke() 方法
数据库连接池(使用动态代理)
package com.situ.chapter5;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.List;/*** 数据库连接池* */
public class ConnectionPool {private static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver";private final String driver;private final String url;private final String username;private final String password;private final int initialSize;// 初始化连接数private int maxConnections = 15;// 最大连接数private List<PooledConnection> connections = new ArrayList<>();// 存储所有数据库连接public List<PooledConnection> getConnections() {return connections;}public ConnectionPool(String driver, String url, String username, String password, int initialSize) {super();this.driver = driver;this.url = url;this.username = username;this.password = password;this.initialSize = initialSize;// 初始化连接池initPool();}public ConnectionPool(String url, String username, String password, int initialSize) {this(MYSQL_DRIVER, url, username, password, initialSize);}public int getMaxConnections() {return maxConnections;}public void setMaxConnections(int maxConnections) {this.maxConnections = maxConnections;}/*** 初始化连接池*/private void initPool() {for (int i = 0; i < initialSize; i++) {// 原始连接Connection conn = buildConnection();// 池连接PooledConnection pc = new PooledConnection();// 创建代理conn = buildConnectionProxy(pc);pc.setConnection(conn);// 存储连接的代理实例connections.add(pc);}}/*** 创建数据库连接* * @return*/private Connection buildConnection() {try {Class.forName(driver);return DriverManager.getConnection(url, username, password);} catch (Exception e) {throw new RuntimeException("获取数据库连接失败,请确认后再试,或联系管理员", e);}}/*** 对某一个连接创建对应的代理* * @param conn* @return*/private Connection buildConnectionProxy(PooledConnection pc) {Connection result = (Connection)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class<?>[] {Connection.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals("close")) {pc.setUsed(false);// 表示释放,不再使用return null;} else {return method.invoke(pc.getConnection(), args);}}});return result;}/*** 获取数据库连接* * @return*/public Connection getConnection() {for (PooledConnection pc : connections) {if (!pc.isUsed()) {pc.setUsed(true);// 设置成使用状态return pc.getConnection();}}if (connections.size() < this.maxConnections) {Connection conn = buildConnection();PooledConnection pc = new PooledConnection();conn = buildConnectionProxy(pc);pc.setConnection(conn);connections.add(pc);pc.setUsed(true);return pc.getConnection();}throw new RuntimeException("连接池已用完");}/*** 维护一个是否使用状态的连接* * @author snow1k* @date 2022/04/06*/public static class PooledConnection {private Connection connection;private boolean used = false;public boolean isUsed() {return used;}public void setUsed(boolean used) {this.used = used;}public Connection getConnection() {return connection;}public void setConnection(Connection connection) {this.connection = connection;}}
}
java基础 day-17 设计模式(单例,工厂,代理),静态动态代理,数据库连接池(动态代理)相关推荐
- java基础—多线程下的单例设计模式的安全问题
//多线程下的单例设计模式 class Sing {//饿汉式不存在安全问题,因为其不是线程同步的private static Sing s = new Sing();private Sing(){} ...
- 25天掌握java基础(八)——static、单例、代码块、继承
文章目录 Demo08-static.单例.代码块.继承 1.static 1.1static静态关键字 1.1.1static修饰成员变量 1.1.2static修饰成员方法 1.1.3static ...
- Java中的程序设计模式--单例与多例
单例设计模式: 就是指一个类只允许产生一个实例化对象. 分析: 要想只能产生一个实例化对象,就意味着使用者不能在外部使用 new 生成一个实例,即表示该类的构造函数是私有的(貌似C++当中没有私有的构 ...
- 【Java】day9--main方法、单例设计模式、继承、方法重写部分知识点总结
(一)main方法 jvm调用main方法,jvm也是一个程序 main方法详解: public:公共 保证该类在任何情况下,jvm都对其方法可见. stat ...
- java设计模式 单例_java设计模式一(单例模式singleton)
1 概述 如果要保证系统里一个类最多只能存在一个实例时,我们就需要单例模式.这种情况在我们应用中经常碰到,例如缓存池.数据库连接池.线程池.一些应用服务实例等.在多线程环境中为了保证实例的唯一性其实并 ...
- spring中的单例工厂SingletonBeanRegistry设计与实现
单例工厂接口为SingletonBeanRegistry,主要是单例的注册,其默认实现为DefaultSingletonBeanRegistry 1.类层次图 2.单例工厂在循环依赖时的流程
- 高仿真的类-单例工厂的顶层设计
/*** 单例工厂的顶层设计*/ public interface V1BeanFactory {/*** 根据beanName从IOC容器中获得一个实例Bean* @param beanName* ...
- Java基础笔记 – 枚举类型的使用介绍和静态导入
Java基础笔记 – 枚举类型的使用介绍和静态导入 本文由 arthinking 发表于404 天前 ⁄ Java基础 ⁄ 暂无评论 ⁄ 被围观 1,433 views+ 1.枚举(Enum): JD ...
- JAVA设计模式 - 单例与工厂模式
前言 设计模式是在前人总结下 , 得出的经验, 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性.继承性和多态性以及类的关联关系和组合关系的充分理解, 接着我们来看设计模式中的两种比较重要的 ...
- java static是单例_JAVA基础-static关键字及单例设计模式
static关键字 基本概念使用static关键字修饰成员变量表示静态的含义, 此时成员变量由对象层级提升为类层级, 也就是整个类只有一份并被所有对象共享. 该成员变量随着类的加载准备就绪, 与是否创 ...
最新文章
- golang 实现 while 和 do……while 循环
- 中山大学新华学院c语言试题,中山大学新华学院国际学院2019级学生入学测试
- 通过完整示例来理解如何使用 epoll
- Apk去签名校验详解
- 设计模式学习笔记——外观(Facade)模式
- 10php1c,PHP程序员,进阶选择C还是C++亦或者别语言
- linux PHY驱动
- 几篇关于【核心网】MME、PGW、SGW和PCRF的介绍
- C++设计模式--观察员
- Could not find acceptable representation
- JavaEE 支付宝支付
- leancloud 怎么绑定域名_云引擎支持绑定加速域名 | LeanCloud 八月变化
- 图像处理中的差分求导计算和相应的卷积核(filter)
- win10系统无法登录ftp服务器失败,win10电脑下ftp连接失败怎么解决
- rtmp协议 java_rtmp协议详解 (一) handshake
- 华为 MA5683T GPON简单业务配置
- Exif信息 处理图片上传时翻转问题
- js正则表达式判断非负数和是否为网址
- 优矿-获取商品期权数据
- background-clip:从box-sizing:border-box属性入手,来了解盒模型
热门文章
- 用java求两个数的最大公因数_Java求两个数的最大公约数及最小公倍数、求多个数的最大公约数及最小公倍数...
- win7旗舰版升级win10
- AntDsign菜单高亮
- 统计学的Python实现-015:调和平均数
- 在Google上做搜索引擎优化 (SEO),最重要的是哪几点?
- CTFSHOW 愚人节欢乐赛WP
- mysql让局域网访问权限_mysql 设置局域网内可访问
- 可以实现psd转png转换器有哪些?这些工具能让你轻松转换图片格式
- Granger格兰杰因果关系的设计、基本假设和额外要求
- TOEFL 9个托福独立写作模板总结