-
2019-03-04 11:05:53更多相关内容
-
Java设计模式之结构型:桥接模式
2021-09-13 17:26:40桥接模式将系统的抽象部分与实现部分分离解耦,使他们可以独立的变化。为了达到让抽象部分和实现部分独立变化的目的,桥接模式使用组合关系来代替继承关系,抽象部分拥有实现部分的接口对象,从而能够通过这个接口...一、什么是桥接模式:
桥接,顾名思义,就是用来连接两个部分,使得两个部分可以互相通讯,桥接模式的作用就是为被分离的抽象部分和实现部分搭桥。在现实生活中一个物品在搭配不同的配件时会产生不同的动作和结果,例如一辆赛车搭配的是硬胎或者是软胎就能够在干燥的马路上行驶,而如果要在下雨的路面行驶,就需要搭配雨胎了,这种根据行驶的路面不同,需要搭配不同的轮胎的变化的情况,我们从软件设计的角度来分析,就是一个系统由于自身的逻辑,会有两个或多个维度的变化,而为了应对这种变化,我们就可以使用桥接模式来进行系统的解耦。 桥接模式将一个系统的抽象部分和实现部分分离,使它们都可以独立地进行变化,对应到上面就是赛车的种类可以相对变化,轮胎的种类可以相对变化,形成一种交叉的关系,最后的结果就是一种赛车对应一种轮胎就能够成功产生一种结果和行为。
桥接模式将系统的抽象部分与实现部分分离解耦,使他们可以独立的变化。为了达到让抽象部分和实现部分独立变化的目的,桥接模式使用组合关系来代替继承关系,抽象部分拥有实现部分的接口对象,从而能够通过这个接口对象来调用具体实现部分的功能。也就是说,桥接模式中的桥接是一个单方向的关系,只能够抽象部分去使用实现部分的对象,而不能反过来。
桥接模式符合“开闭原则”,提高了系统的可拓展性,在两个变化维度中任意扩展一个维度,都不需要修改原来的系统;并且实现细节对客户不透明,可以隐藏实现细节。但是由于聚合关系建立在抽象层,要求开发者针对抽象进行编程,这增加系统的理解和设计难度。
所以,桥接模式一般适用于以下几种应用场景:
- (1)系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,则可以通过桥接模式使他们在抽象层建立一个关联关系;
- (2)系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时
- (3)一个类存在两个独立变化的维度,而这两个维度都需要进行扩展。
二、UML结构图:
- 抽象化角色 Abstraction:定义抽象的接口,包含一个对实现化角色的引用,抽象角色的方法需要调用实现化角色;
- 扩展抽象化角色 RefinedAbstraction:抽象化角色的子类,一般对抽象部分的方法进行完善和扩展,实现父类中的业务方法,并通过组合/聚合关系调用实现化角色中的业务方法
- 实现化角色 Implementor:定义具体行为、具体特征的应用接口,供扩展抽象化角色使用,一般情况下是由实现化角色提供基本的操作,而抽象化角色定义基于实现部分基本操作的业务方法;
- 具体实现化角色 ConcreteImplementor:完善实现化角色中定义的具体逻辑。
三、代码实现:
Implementor 接口类:
public interface Implementor { void operationImpl(); }
ConcreteImplementor 接口实现类:
public class ConcreteImplementorA implements Implementor{ @Override public void operationImpl() { //具体实现 } } public class ConcreteImplementorB implements Implementor{ @Override public void operationImpl() { //具体实现 } }
Abstraction 抽象类:
public abstract class Abstraction { private Implementor implementor; public Abstraction(Implementor implementor) { this.implementor = implementor; } public void operation() { implementor.operationImpl(); } }
RefinedAbstraction 抽象类的具体实现:
public class RefinedAbstraction extends Abstraction{ public RefinedAbstraction(Implementor implementor) { super(implementor); } public void refinedOperation() { //对 Abstraction 中的 operation 方法进行扩展 } }
看了这段通用代码之后,桥接模式的结构应该就很清楚了,需要注意的是 RefinedAbstraction 根据实际情况是可以有多个的。 当然上面的 UML 类图和通用代码只是最常用的实现方式而已,在实际使用中可能会有其他的情况,比如 Implementor 只有一个类的情况,虽然这时候可以不去创建 Implementor 接口,精简类的层次,但是我建议还是需要抽象出实现部分的接口。
四、JDBC源码解析-桥接模式:
该部分引用自:JDBC和桥接模式 - 枯落 - 博客园
Java 中,我们使用 JDBC 连接数据库时,在各个数据库之间进行切换,基本不需要动太多的代码,原因就是使用了桥接模式,JDBC 提供统一接口,每种类型的数据库提供各自的实现,然后由桥接类创建一个连接数据库的驱动,使用某一个数据库的时候只需要切换一下就行。接下来我们就对 JDBC 的源码做下剖析:
通过原生JDBC API连接MySQL数据库,则有如下示例代码:
Class.forName("com.mysql.cj.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://<host>:<port>/<database>");
短短两行代码难以看出桥接模式的结构,下面先对源码进行一定的分析,理解各个类和接口之间的关系:
1、源码分析:
(1)Class.forName() 方法:
该方法将返回与给定字符串名的类或接口相关联的 java.lang.Class 类对象,用于在程序运行时动态加载该类或该接口到当前线程中,如果 Class.forName() 加载的是一个类,也会执行类中包含的static { } 静态代码段
(2)com.mysql.cj.jdbc.Driver 类:
MySQL 将具体的 java.sql.Driver 接口的实现放到了 NonRegisteringDriver 中,com.mysql.cj.jdbc.Driver 类仅包含一段静态代码,具体类图如下:
其中最关键的是静态代码段中的 DriverManager.registerDriver(new Driver()) ,它会在客户端调用Class.forName() 方法加载 com.mysql.cj.jdbc.Driver 类的同时被执行,Driver 类自身的一个实例被注册到 DriverManager(即保存到 DriverManager 的静态字段 registeredDrivers 内),注册过程的源码如下:
public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException { /* Register the driver if it has not already been added to our list */ if(driver != null) { registeredDrivers.addIfAbsent(new DriverInfo(driver, da)); } else { // This is for compatibility with the original DriverManager throw new NullPointerException(); } println("registerDriver: " + driver); }
registeredDrivers 静态字段的类型是实现了 List 接口的 CopyOnWriteArrayList 类,它能够保存进一步封装 java.sql.Driver 接口的 DriverInfo 类实例,DriverInfo 类的声明代码如下:
class DriverInfo { final Driver driver; DriverAction da; DriverInfo(Driver driver, DriverAction action) { this.driver = driver; da = action; } // …… }
DriverInfo 还包装了 DriverAction,DriverAction 会在Driver被取消注册时被调用,在 MySQL 的 Driver 在向 DriverManager 进行注册时,DriverAction 被设置为 null
(3)DriverManager 类:
由上面的分析可得,Class.forName() 方法调用后,com.mysql.cj.jdbc.Driver 类被加载,并执行static { } 静态代码段,将 com.mysql.cj.jdbc.Driver 类实例注册到 DriverManager 中。然后,客户端会调用 DriverManager.getConnection() 方法获取一个 Connection 数据库连接实例,该方法的部分源码如下:
private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException { // …… for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if(isDriverAllowed(aDriver.driver, callerCL)) { try { println(" trying " + aDriver.driver.getClass().getName()); Connection con = aDriver.driver.connect(url, info); if (con != null) { // Success! println("getConnection returning " + aDriver.driver.getClass().getName()); return (con); } } catch (SQLException ex) { if (reason == null) { reason = ex; } } } else { println(" skipping: " + aDriver.getClass().getName()); } } // …… }
DriverManager.getConnection() 方法会遍历 registeredDrivers 静态字段,获取字段内保存的每一个 Driver 来尝试响应客户端的数据库连接请求,若所有 Driver 都连接数据库失败,则提示连接失败信息
(4)Connection接口:
Connection 代表和特定数据库的连接会话,能够执行SQL语句并在连接的上下文中返回执行结果。因此,DriverManager.getConnection() 方法返回的 Connection 数据库连接实例根据不同的数据库有不同的实现,MySQL 的 Connection 接口实现关系如下:
2、源码类图:
根据源码的分析,绘制类图如下:
对 Driver 和 Connection 进行抽象,绘制类图如下:
桥接模式通过聚合关系代替继承关系,实现抽象化和实现化部分的解耦。以上述 JDBC 在 MySQL 中的简略类图为例,抽象化部分有 DriverManager,实现化部分有 Driver 接口和 Connection 接口。对于不同的数据库,Driver接口和Connection接口都有自己独特的实现类。
但是,和 Driver 接口不同的是,Connection 接口与 DriverManager 类的关系只是联系较弱的依赖关系,并不符合桥接模式的定义和特点。因此,在考虑桥接模式的情况下,可以再次将类图进行简化:
最后,我们将其它数据库的Driver接口实现也考虑在内,绘制类图如下:
桥接模式中的实现化角色 (Implementor) 对应上图的 Driver 接口,具体实现化 (Concrete Implementor) 角色对应 MysqlDriver、OracleDriver 和 MariadbDriver,扩展抽象化 (Refined Abstraction) 角色对应 DriverManager,不具有抽象化 (Abstraction) 角色作为扩展抽象化角色的父类
3、对 JDBC 的观点:
(1)观点一:JDBC 的桥接模式是一中简化的桥接模式
桥接模式的主要应用场景是某个类存在两个独立变化的维度,且这两个维度都需要进行扩展,而现在仅有 Driver 一个变化维度,DriverManager 没有抽象化父类,它本身也没有任何子类,因此我认为,在 JDBC 中,是一种简化的桥接模式。
倘若 JDBC 针对 Connection 接口的设计不是将它作为 Driver 和 DriverManager 的"依赖"来处理,而是也作为一个变化的维度加入到桥接模式,或许能够更好地体现JDBC对桥接模式的实现,一种"假想"的桥接模式如下:
(2)观点二:JDBC采用的是策略模式而不是桥接模式
问题来源知乎:jdbc是桥接模式还是策略模式? - 知乎
因为这确实和策略模式十分相似,如果把桥接模式的抽象部分简化来看,不去设计Abstraction,也就是用 Refined Abstraction 代替 Abstraction,那么就类似于策略模式的 Context 来使用接口的对象。
但是,桥接模式和策略模式的目的是不一样的,策略模式属于对象行为模式(描述对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责),它的目的是封装一系列的算法,使得算法可以相互替代,并在程序运行的不同时刻选择合适的算法。而桥接模式属于对象结构模式(描述如何将对象按某种布局组成更大的结构),它的目的是将抽象与实现分离,使它们可以独立变化
因此,从设计的目的来看,JDBC采用的并不是策略模式,在一段程序中数据库驱动并不存在频繁地相互替换
(3)观点三:变化的维度一个是平台,另一个是数据库
问题来源:https://www.unclewang.info/learn/java/771/?tdsourcetag=s_pctim_aiomsg
这是我认同的一个观点,引用原文的话:变的是平台和数据库,平台在 JVM 这个层面就解决了,因为所有操作系统 Java 基本都会提供对应JDK,这也是 "Once Write,Run AnyWhere" 的原因。而数据库则是依托公司的具体实现,各个公司都提供对应的 Driver 类,我用 DriverManager 类进行懒加载.
考虑数据库的实际应用场景,我们可能在不同的操作系统上使用不同的数据库,但是JVM的平台无关性使得我们不再有操作系统层面上的变化。假设不存在JVM,那么不同的客户端加载和运行数据库驱动程序的代码自然也各有不同,即 DriverManager 会因操作系统的变化而变化,不同的操作系统可以有不同的注册 Driver 的方式,不过因为存在JVM,我们现在不再有"平台"这一变化维度了
(4)观点四:变化的维度一个是客户端应用系统,另一个是数据库
问题来源:java设计模式-桥梁模式(桥接模式 Bridge) - 简书
一个比较独特的观点,引用原文的话:应用系统作为一个等级结构,与 JDBC 驱动器这个等级结构是相对独立的,它们之间没有静态的强关联。应用系统通过委派与JDBC驱动器相互作用,这是一个桥梁模式的例子。
原文笔者不认为 DriverManager 作为 Refined Abstraction 角色存在,而是视作两个变化维度之间的一个"过渡",原本的"桥"是 Abstraction 和 Implementor 之间的组合/聚合关系,而现在DriverManager 类本身成为了"桥",可以看作是桥梁模式的一个变体
(5)观点五:变化的维度一个是 Driver,一个是 Connection:
如果从观点四的原文笔者的角度看,把 DriverManager 类本身作为"桥",那么我们还可以提出一种新的观点,绘制类图如下:
设计模式系列文章:
参考博客:
-
设计模式(二)结构型模式
2018-08-04 20:58:08Java 中一般认为有23 种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌握。 下面列出了所有的设计模式。... 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模...
Java 中一般认为有23 种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌握。
下面列出了所有的设计模式。需要掌握的设计模式我单独列出来了,当然能掌握的越多越好。
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。总结:每一种设计模式,代码去理解实现方式,根据结构图记忆理解。本文没有给出具体代码,可以在码云下载代码使用,本文适合不断翻看理解这些设计模式
码云代码:https://gitee.com/huopusa/arithmetic.git六、适配器模式 adapter
分类
类适配器、对象适配器、接口适配器
UML图
适配器模式应用场景
类适配器与对象适配器的使用场景一致,仅仅是实现手段稍有区别,二者主要用于如下场景
(1)想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
(2)我们有一个类,想将其设计为可重用的类(可被多处访问),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
接口适配器使用场景:
1)想要使用接口中的某个或某些方法,但是接口中有太多方法,我们要使用时必须实现接口并实现其中的所有方法,可以使用抽象类来实现接口,并不对方法进行实现(仅置空),然后我们再继承这个抽象类来通过重写想用的方法的方式来实现。这个抽象类就是适配器。
参照博文:
https://blog.csdn.net/yujin753/article/details/46287643
http://www.cnblogs.com/V1haoge/p/6479118.html七、装饰器模式 decorator
https://www.cnblogs.com/jzb-blog/p/6717349.html
Component为统一接口
,也是装饰类和被装饰类的基本类型。
ConcreteComponent为具体实现类,也是被装饰类,他本身是个具有一些功能的完整的类。
Decorator是装饰类,实现了Component接口的同时还在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。而Decorator本身,通常采用默认实现,他的存在仅仅是一个声明:我要生产出一些用于装饰的子类了。而其子类才是赋有具体装饰效果的装饰产品类。
ConcreteDecorator是具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。可以通过构造器声明装饰哪种类型的ConcreteComponent,从而对其进行装饰。
优点:
装饰器模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
代码:public interface ICar { void move(); } //ConcreteComponent 具体构件角色(真实对象) class Car implements ICar { @Override public void move() { System.out.println("陆地上跑!"); } } class SuperCar implements ICar { private ICar car; public SuperCar(ICar car) { this.car = car; } @Override public void move() { car.move(); } } //ConcreteDecorator具体装饰角色 class FlyCar extends SuperCar { public FlyCar(ICar car) { super(car); } public void fly() { System.out.println("天上飞"); } @Override public void move() { super.move(); fly(); } } //ConcreteDecorator具体装饰角色 class WaterCar extends SuperCar { public WaterCar(ICar car) { super(car); } public void swim() { System.out.println("水里游"); } @Override public void move() { super.move(); swim(); } } //ConcreteDecorator具体装饰角色 class AICar extends SuperCar { public AICar(ICar car) { super(car); } public void autoMove() { System.out.println("自动跑"); } @Override public void move() { super.move(); autoMove(); }
测试客户端:
public class Client { public static void main(String[] args) { ICar car = new Car(); car.move(); System.out.println("------------增加新的功能:飞行"); ICar flycar = new FlyCar(car); flycar.move(); System.out.println("------------增加新的功能:水里游"); ICar waterCar = new WaterCar(car); waterCar.move(); System.out.println("------------增加两个新的功能,飞行,水里游"); ICar waterCar2 = new WaterCar(flycar); waterCar2.move(); System.out.println("------------累加3个新的功能,飞行,水里游,自动驾驶"); ICar superCar = new AICar(waterCar2); superCar.move(); } }
运行结果:
八、代理模式 proxy
特点: 1、 执行者、 被代理人 2、 对于被代理人来说, 这件事情是一定要做的, 但是我自己又不想做或者没有时间做, 找代理。 3、 需要获取到被代理的人个人资料。 4、关心过程
例子: 租房中介: 中介和你 火车票黄牛: 黄牛和你 媒人: 媒婆和你 明星经纪人: 经纪人和明星 刘德华要开演唱会(长沙) 、 准备工作和善后工作
AOP中使用场景
事务代理(声明式事务, 哪个方法需要加事务, 哪个方法不需要加事务)
日志监听
假如我们定义了一个service 方法
开启一个事务(open) 代理来做
事务的执行 执行我们的service方法
监听到是否有异常, 可能需要根据异常的类型来决定这个事务是否要回滚还是继续提交 代理来做
(commit/rollback) 代理来做
事务要关闭(close) 代理来做参照
https://blog.csdn.net/qq_33214833/article/details/70230891
注:代理模式应用比较广泛,使代码开发更加灵活九、外观模式 Facade (门面模式)
概念:
外观模式(Facade),他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式属于结构性模式。为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。
uml图
简单来说,该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用。这个模式中,设计到3个角色。
1).门面角色:外观模式的核心。它被客户角色调用,它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合。
2).子系统角色:实现了子系统的功能。它对客户角色和Facade时未知的。它内部可以有系统内的相互交互,也可以由供外界调用的接口。
3).客户角色:通过调用Facede来完成要实现的功能
注:因门面模式Spring+接口调用应用太广泛,没有写具体代码
十、桥接模式 bridge
https://www.cnblogs.com/lixiuyu/p/5923160.html1.桥接模式的优点
(1)实现了抽象和实现部分的分离
桥接模式分离了抽象部分和实现部分,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,分别定义接口,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。
(2)更好的可扩展性
由于桥接模式把抽象部分和实现部分分离了,从而分别定义接口,这就使得抽象部分和实现部分可以分别独立扩展,而不会相互影响,大大的提供了系统的可扩展性。
(3)可动态的切换实现
由于桥接模式实现了抽象和实现的分离,所以在实现桥接模式时,就可以实现动态的选择和使用具体的实现。
(4)实现细节对客户端透明,可以对用户隐藏实现细节。
2.桥接模式的缺点
(1)桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。
(2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性。
3.桥接模式的使用场景
(1)如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
(2)抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
(3)一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
(4)虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
(5)对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用
代码/** * 定义接口--被实现者 */ public interface Implementor { public void operation(); }
/** * 实现者A */ public class ConcreateImplementorA implements Implementor { @Override public void operation() { System.out.println("这个是ConcreateImplementorA的operation方法"); } }
/** * 实现者B */ public class ConcreateImplementorB implements Implementor { @Override public void operation() { System.out.println("这个是ConcreateImplementorB的operation方法"); } }
/** * 桥接类 */ public abstract class Abstraction { private Implementor implementor; public Implementor getImplementor() { return implementor; } public void setImplementor(Implementor implementor){ this.implementor = implementor; } // 引用接口 protected void operation(){ implementor.operation(); } }
/** * 桥接实现类 */ public class RefinedAbstraction extends Abstraction { @Override protected void operation() { super.operation(); } }
/** * client 调用测试 */ public class BridgeTest { public static void main(String[] args) { Abstraction abstraction = new RefinedAbstraction(); //调用第一个实现类 abstraction.setImplementor(new ConcreateImplementorA()); abstraction.operation(); //调用第二个实现类 abstraction.setImplementor(new ConcreateImplementorB()); abstraction.operation(); } }
十一、组合模式 Composite
1、UML结构
实例图
2、角色组成
抽象构件角色(component):是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。这个接口可 以用来管理所有的子对象。(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
树叶构件角色(Leaf):在组合树中表示叶节点对象,叶节点没有子节点。并在组合中定义图元对象的行为。
树枝构件角色(Composite):定义有子部件的那些部件的行为。存储子部件。在Component接口中实现与子部件有关的操作。
客户角色(Client):通过component接口操纵组合部件的对象。3、组合模式的优缺点
优点:
组合模式使得客户端代码可以一致地处理对象和对象容器,无需关系处理的单个对象,还是组合的对象容器。
将”客户代码与复杂的对象容器结构“解耦。
可以更容易地往组合对象中加入新的构件。
缺点: 使得设计更加复杂。客户端需要花更多时间理清类之间的层次关系。(这个是几乎所有设计模式所面临的问题)。
注意的问题:
有时候系统需要遍历一个树枝结构的子构件很多次,这时候可以考虑把遍历子构件的结构存储在父构件里面作为缓存。
客户端尽量不要直接调用树叶类中的方法(在我上面实现就是这样的,创建的是一个树枝的具体对象;),而是借用其父类(Graphics)的多态性完成调用,这样可以增加代码的复用性。
4、组合模式的使用场景
在以下情况下应该考虑使用组合模式:
当想表达对象的部分-整体的层次结构时。
希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象时。
参考:https://www.cnblogs.com/snaildev/p/7647190.html十二、享元模式 Flyweight Pattern
http://www.cnblogs.com/java-my-life/archive/2012/04/26/2468499.html
享元模式:以共享的方式高效的支持大量的细粒度对象。通过复用内存中已存在的对象,降低系统创建对象实例的性能消耗。
java的 String 类型就是享元模式
单纯享元模式所涉及到的角色如下:
● 抽象享元(Flyweight)角色 :给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。
● 具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
● 享元工厂(FlyweightFactory)角色 :本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
复合享元角色所涉及到的角色如下:
● 抽象享元(Flyweight)角色 :给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。
● 具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
● 复合享元(ConcreteCompositeFlyweight)角色 :复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称作不可共享的享元对象。
● 享元工厂(FlyweightFactory)角色 :本角 色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有 一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个 合适的享元对象。
享元模式的优缺点
享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:
● 享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
● 享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。享元模式实例
其实在Java中就存在这种类型的实例:String。
Java中将String类定义为final(不可改变的),JVM中字符串一般保存在字符串常量池中,这个字符串常量池在jdk 6.0以前是位于常量池中,位于永久代,而在JDK 7.0中,JVM将其从永久代拿出来放置于堆中。
我们使用如下代码定义的两个字符串指向的其实是同一个字符串常量池中的字符串值。String s1 = "abc"; String s2 = "abc";
如果我们以s1==s2进行比较的话所得结果为:true,因为s1和s2保存的是字符串常量池中的同一个字符串地址。这就类似于我们今天所讲述的享元模式,字符串一旦定义之后就可以被共享使用,因为他们是不可改变的,同时被多处调用也不会存在任何隐患。
享元模式使用的场景:
当我们项目中创建很多对象,而且这些对象存在许多相同模块,这时,我们可以将这些相同的模块提取出来采用享元模式生成单一对象,再使用这个对象与之前的诸多对象进行配合使用,这样无疑会节省很多空间。参照例子(更加形象的例子):https://www.cnblogs.com/V1haoge/p/6542449.html
-
以下设计模式中,哪一项不属于结构性模式
2017-03-20 20:28:50以下设计模式中,哪一项不属于结构性模式? A 适配器模式 B 代理模式 C 命令模式 D 装饰模式 正确答案 : C知识点创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型...美团2016校园招聘 研发工程师(一)
以下设计模式中,哪一项不属于结构性模式?
A 适配器模式
B 代理模式
C 命令模式
D 装饰模式正确答案 : C
知识点
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
-
设计模式 - 结构型设计模式 - 适配器模式(Java)
2019-01-23 20:24:55对象适配器模式 来看一个《Head First 设计模式》中的一个例子,我们稍微修改了一下,看看怎么将鸡适配成鸭,这样鸡也能当鸭来用。因为,现在鸭这个接口,我们没有合适的实现类可以用,所以需要适配器。 public ... -
数据结构&设计模式篇
2020-06-23 10:46:34动态代理有几种实现? java的动态代理技术的实现主要有两种方式: 1.JDK原生动态代理 2.CGLIB动态代理 JDK原生动态代理是Java原生支持的,...常见的数据结构有哪些? 问题回答: 一共八大数据结构分类 1.数组 2.队列 -
结构型模式分类与简介
2019-03-06 09:31:11在GoF设计模式中,结构型模式有: 1.适配器模式 Adapter 适配器模式是将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 ... -
Java常见设计模式总结
2021-09-18 17:18:54设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式于己于人于系统都...总体来说,设计模式分为三大类:5种创建型模式、7种结构型模式、11种行为型模式 -
设计模式——行为型模式
2019-04-23 21:47:511. 策略模式(Strategy) 2.状态模式(State) 3.责任链模式(Chain Of Responsibility) 4.解释器模式(Interpreter) 5.命令模式(Command) 6.观察者模式(Observer) 7.备忘录模式(Memento) 8.迭代器模式... -
Java设计模式_(结构型)_外观模式
2017-09-25 14:54:33引用百科外观模式(Facade),为子系统中的一组接口提供一...适用场景在以下情况下可以考虑使用外观模式:(1)设计初期阶段,应该有意识的将不同层分离,层与层之间建立外观模式。(2) 开发阶段,子系统越来越复杂,增加 -
Java设计模式之结构型:适配器模式
2018-11-01 23:05:23适配器模式主要用于将一个类的接口转化成客户端希望的目标类格式,使得原本不兼容的类可以在一起工作,将目标类和适配者类解耦;同时也符合“开闭原则”,可以在不修改原代码的基础上增加新的适配器类;将具体的实现... -
什么是设计模式?程序员如何学好设计模式?
2021-11-30 00:15:58前几天,我给大家介绍了算法和数据结构的基础知识。后来又有小伙伴私信问我:“小灰,你能不能也讲一讲设计模式的相关知识?”没问题!对于程序员来说,设计模式也是必须要掌握的一项核心知识,我今天就... -
Java设计模式之结构型:外观模式
2018-11-02 12:12:38使用外观模式有以下几点好处:更加易用、松散耦合、更好的划分访问层次。但是如果外观模式对子系统类做太多的限制则减少了可变性和灵活性,所以外观模式适用于为复杂子系统提供一个简单接口,提高系统的易用性场景 ... -
设计模式(结构型)之装饰者模式(Decorator Pattern)
2015-04-30 17:06:20装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。在... -
Java设计模式_(结构型)_组合模式
2017-09-22 15:37:56引用百科组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 "组合对象" ... -
设计模式之十一种行为型模式(附实例和详解)
2017-11-23 15:17:42本文主要讲行为型模式,创建型模式和结构型模式可以看博主的另外两篇文章:J设计模式之五大创建型模式(附实例和详解)、 设计模式之七大结构型模式(附实例和详解)。行为型模式细分为如下11种:策略模式、模板方法... -
设计模式——设计模式概述
2019-10-12 08:07:49软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式主要是为了解决某类重复出现的问题而出现的一套成功或有效的解决方案。设计模式提供... -
设计模式汇总:结构型模型(上)
2016-05-12 10:11:43总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元... -
Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)
2021-09-12 17:57:40工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:简单工厂模式、工厂...当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,保证客户端始终只使用同一个产品族 -
Carson带你学设计模式:这是一份全面 & 详细的设计模式学习指南
2021-08-30 11:05:39设计模式其实并不神秘,今天carson将带你了解一切关于设计模式的知识。 Carson带你学设计模式系列文章 这是一份全面 & 详细的设计模式学习指南 Carson带你学设计模式:单例模式(Singleton) Carson带你学设计... -
大话设计模式之爱你一万年:第十二章 结构型模式:代理模式:代理无所不能:3.代理模式之动态代理
2020-12-22 14:30:11JDK动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类: (1) Interface InvocationHandler:该接口中仅定义了一个方法 public Object invoke(Object proxy, Method method, Object[] args) 在... -
设计模式与软件体系结构【期末全整理答案】
2020-07-13 19:01:19若本文对你有帮助,请点赞、关注我呦! 期末试题基本出自这些题,请提前复制黏贴到word文档里,方便考试时直接查找。 单选题汇总 ...2、常用的基本设计模式可分为(A)。 A.创建型、结构型和行为型 ... -
大话设计模式之爱你一万年:第十章 结构型模式:组合模式:爱如此简单:3.组合模式在Spring框架和JDK中的...
2020-12-22 14:13:42这一节我们看看组合模式在Spring框架和JDK中的应用: 一、Spring中的应用 1.1 WebMvcConfigurerComposite 我们在使用Java注解对springMVC进行配置时,通常是使用以下方式: 那我们的这个WebMvcConfig是谁... -
软件体系结构与设计模式——课程总体介绍(01-03)
2019-01-23 23:04:01仅供参考,以下是个人的课堂笔记,只有设计模式部分,这门课的sk老师非常负责,在学生中口碑很好,如果认真听课,课后及时总结,最后会更易读懂代码的架构以及为何这样设计的原因,对编程也有很大的帮助。... -
设计模式(一)设计模式的分类与区别
2020-05-17 11:21:37设计模式的分类、设计模式的原则、设计模式的适用场景、设计模式的区别 -
按照目的来分,设计模式可以分为创建型模式、结构型模式和行为型模式。
2012-01-05 17:15:54按照目的来分,设计模式可以分为创建型模式、结构型模式和行为型模式。 创建型模式用来处理对象的创建过程;结构型模式用来处理类或者对象的组合;行为型模式用来对类或对象怎样交互和怎样分配职责进行描述。 ... -
深入理解设计模式-工厂方法模式
2022-02-18 14:40:23文章目录前言一、定义二、使用场景三、代码样例1.需求2.类图3.工厂相关类4.产品相关类5.... 前言 在现实生活中社会分工越来越...在简单工厂模式中,我们提到了简单工厂模式违背了开闭原则,而“工厂方法模式”是对简单工厂 -
设计模式之行为型模式
2020-08-19 17:22:50行为型模式 一、模板方法模式 (一)定义:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 (二)模式说明: 例如,去银行办理业务... -
设计模式
2019-07-22 09:33:22设计模式简介 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过... -
23种设计模式分析(4):结构型模式
2014-04-05 22:37:27Composite(复合、合成、组合)模式是一种结构型模式,定义:将对象组合成树形结构以表示“部分-整体”的层次结构,它使得客户对单个对象和复合对象的使用具有一致性。 这里的复合对象是很多单个对象的“组合”...