-
2022-04-14 16:02:36
一:创建型五个模式概念
单例模式、工厂方法、抽象工厂、建造者模式、原形模式
创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。二:五个模式以及代码实现
2.1 单例模式
基本概念:
单例模式的方法创建的类在当前进程中只有一个实例internal class Single { private static Single single; //建立一个全局对象 private Single() //将构造函数进行隐藏,外部不可访问 { } public static Single GetSingle() { if (single ==null) //如果第一次访问的话,就完成对象初始化 { single = new Single(); } return single; } }
单例模式一共有三个要点。
1.某个类只能有一个实例;
2.它必须自行创建这个实例。
3.它必须向整个系统提供这个实例。
对应到代码上来说就是:私有构造函数、私有静态对象、共有创建获取的方法。2.2工厂方法模式
工厂三姐妹分别是简单工厂、工厂方法、抽象工厂,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类。工厂方法有四个核心,分别为抽象工厂;具体工厂;抽象产品;具体产品。
//抽象的工厂 internal interface ICreator { //返回一个产品 IProduct FactoryMethod(); } //抽象的产品 interface IProduct { } //具体的工厂 class ConcreteCreator : ICreator { //创建的是一个具体的产品 public IProduct FactoryMethod() { return new ConcreteProduct(); } } //具体的产品 class ConcreteProduct : IProduct { }
最后创建的是具体的产品。如果增加了新的需求的话,我们可以增加一个新的工厂,然后增加一个新的产品。客户端依赖的是抽象的产品和抽象的工厂
2.3 抽象工厂模式
抽象工厂模式的主要角色如下。
抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
也就是说和工厂方法相比,抽象工厂抽象的是各类工厂,具体工厂可以实现为多个工厂。抽象产品也有多个,并且每个抽象产品下面都可以实现多个具体的产品。
2.4建造者模式
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
建造者由产品、抽象建造者、具体建造者、指挥者、四个部分组成。//产品 class Product { //产品属性 private string A; private string B; private string C; //给产品属性赋值的方法 public void setPartA(string A) { this.A = A; } public void setPartB(string B) { this.B = B; } public void setPartC(string C) { this.C = C; } } //抽象的建造者 abstract class Builder { //创建产品对象 protected Product product = new Product(); //产品对象的具体构造,父类定义了构造结构,子类具体构造 public abstract void BuildPartA(); public abstract void BuildPartB(); public abstract void BuildPartC(); //获得产品对象 public Product GetProduct() { return product; } } //具体建造者 class ConcreteBuilder1 : Builder { public override void BuildPartA() { product.setPartA("属性1A"); } public override void BuildPartB() { product.setPartB("属性1B"); } public override void BuildPartC() { product.setPartC("属性1C"); } } //具体建造者2 class ConcreteBuilder2 : Builder { public override void BuildPartA() { product.setPartA("属性2A"); } public override void BuildPartB() { product.setPartB("属性2B"); } public override void BuildPartC() { product.setPartC("属性2C"); } } //指挥者 class Direcotr { //声明一个建造者对象 private Builder builder; //指挥者的构造函数,因为指挥者类就是为了指挥建造者建造产品的,所以在构造函数里传入 public Direcotr(Builder builder) //这里传进来的是具体的建造者的对象 { this.builder = builder; } //下面的方法为具体建造过程方法 public Product Construct() { builder.BuildPartA(); //先建造1 builder.BuildPartB(); //在建造2 builder.BuildPartC(); //在建造3 return builder.GetProduct(); //获得建造好得对象 } }
2.5原型模式
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
原型模式包含以下主要角色。抽象原型类:规定了具体原型对象必须实现的接口。 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
原型模式的克隆分为浅克隆和深克隆。
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
//抽象类 abstract class Prototype { private string id; public Prototype(string id) { this.id = id; } public string Id { get { return this.id; } } public abstract Prototype Clone(); } class ConcretePrototype1 : Prototype { public ConcretePrototype1(string id) : base(id) { } public override Prototype Clone() { return (Prototype)this.MemberwiseClone(); } }
更多相关内容 -
java设计模式之创建型设计模式
2021-10-16 12:19:00创建型设计模式: 抽象工厂(Abstract Factory): 用途:提供一个接口以创建一系列相关或相互依赖的对象,而无需指定具体的类。 场景: 一个系统要独立于它的产品的创建。 一个系统要由多个产品系列中的一个来...创建型设计模式:
抽象工厂(Abstract Factory):
-
用途:提供一个接口以创建一系列相关或相互依赖的对象,而无需指定具体的类。
-
场景:
- 一个系统要独立于它的产品的创建。
- 一个系统要由多个产品系列中的一个来配置。
- 强调一系列相关的产品对象的设计以便进行联合使用。
- 提供一个产品类库,但只对外提供它们的接口而不是实现
-
结构图: 创建一系列相关的对象
-
已知应用:JDK中的Collection,Map
-
工厂方法(Factory Method):
-
用途:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
-
场景:
- 一个类不知道它所创建的对象的类。
- 一个类希望由它的子类来指定它所创建的对象。
- 多用于框架代码中,面向接口编程。
-
结构图:创建一个对象
-
已知应用:
- JDK中的ThreadPoolExecutor的阻塞队列
- AbstractExecutorService.submit方法,在ScheduledThreadPoolExecutor中返回不同的Future
-
建造者(Builder):
-
用途:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
-
场景:
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
-
结构图: 定义一系列的步骤去创建一类产品
-
已知应用
- JDK中的StringBuilder
- Spring中的BeanDefinitionBuilder
单例模式
-
用途:涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
-
场景:
- 要求生产唯一序列号。
- WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
-
结构图:
原型模式
-
用途:实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式
-
场景:
- 资源优化场景。
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景。
- 通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
- 一个对象多个修改者的场景。
-
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
-
结构图:clone()方法
-
-
设计模式之实验二: 创建型设计模式实验
2020-12-16 10:47:48实验项目二: 创建型设计模式实验 (1)实验目的与原理 ①结合实例,熟练绘制创建型设计模式结构图。 ②结合实例,熟练使用Java面向对象编程语言实现创建型设计模式。 ③通过编程实践,理解每一种创建型设计模式的概念...实验项目二: 创建型设计模式实验
(1)实验目的与原理
①结合实例,熟练绘制创建型设计模式结构图。
②结合实例,熟练使用Java面向对象编程语言实现创建型设计模式。
③通过编程实践,理解每一种创建型设计模式的概念和内涵、结构、优缺点以及应用场景。
(2)实验内容与步骤
①使用简单工厂模式设计一个可以创建不同几何形状( Shape)(例如圆形( Circle).、矩形 Rectangle)和三角形( ( Triangle)等的绘图工具类,每个几何图形均具有绘制方法daw()和擦除方法 erase(),要求在绘制不支持的几何图形时,抛出一个 UnsupportedShapeException异常。绘制类图并编程模拟实现。②在某网络管理软件中,需要为不同的网络协议提供不同的连接类,例如针对POP3协议的连接类POP3Connection、针对IMAP协议的连接类 IMAPConnection、针对HTTP协议的连接类 HTTPConnection等。由于网络连接对象的创建过程较为复杂,需要将其创建过程封装到专门的类中,该软件还将支持更多类型的网络协议。现采用工厂方法模式进行设计,绘制类图并编程模拟实现。
③某系统为了改进数据库操作的性能,用户可以自定义数据库连接对象 Connection和语句对象 Statement,针对不同类型的数据库提供不同的连接对象和语句对象,例如提供 Oracle或 MySQL专用连接类和语句类,而且用户可以通过配置文件等方式根据实际需要动态更换系统数据库。使用抽象工厂模式设计该系统,绘制对应的类图并编程模拟实现。
④在某赛车游戏中,赛车包括方程式赛车、场地野赛车、运动汽车、卡车等类型,不同类型的赛车的车身、发动机、轮胎、变速箱等部件有所区别。玩家可以自行选择赛车类型,系统将根据玩家的选择创建出一辆完整的赛车。现采用建造者模式实现赛车的构建,绘制对应的类图并编程模拟实现
⑤某在线招聘网站中,用户可以创建一个简历模板。针对不同的工作岗位,可以复制该简历模板并进行适当修改后,生成一份新的简历。在复制简历时,用户可以选择是否复制简历中的照片:如果选择“是”,则照片将一同被复制,用户对新简历中的照片进行修改不会影响到简历模板中的照片,对模板进行修改也不会影响到新简历;如果选择“否”,则直接引用简历模板中的照片,修改简历模板中的照片将导致新简历中的照片一同修改,反之亦然。现采用原型模式设计该简历复制功能并提供浅克隆和深克隆两套实现方案,绘制对应的类图并编程模拟实现。
⑥某Web性能测试软件中包含一个虚拟用户生成器( Virtual User Generator)。为了避免生成的虚拟用户数量不一致,该测试软件在工作时只允许启动唯一一个虚拟用户生成器。采用单例模式设计该虚拟用户生成器,绘制类图并分别使用饿汉式单例、双重检测锁等二种方式编程模拟实现。
(3)实验过程
第一题:简单工厂模式实现创建不同几何图形
结构类图
实现代码:略
模拟测试截图
第二题:工厂方法模式实现不同网络协议的连接
结构类图
实现代码:
略
模拟测试截图
第三题:抽象工厂模式实现数据库的连接
结构类图
实现代码:
略
模拟测试截图
第四题:建造者模式实现赛车的构建
结构类图
实现代码:
略
模拟测试截图
第五题:原型模式通过浅克隆和深克隆方法实现该简历复制功能
结构类图
实现代码:
略
模拟测试截图
第六题:单例模式设计虚拟用户生成器,使用饿汉式和双重检测
结构类图
实现代码:
略
模拟测试截图
详细的代码及操作 -
Java常见设计模式总结
2021-09-18 17:18:54设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式于己于人于系统都...总体来说,设计模式分为三大类:5种创建型模式、7种结构型模式、11种行为型模式一、设计模式总述:
1、什么是设计模式:
设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式于己于人于系统都是多赢的,它使得代码编写真正工程化,它是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。总体来说,设计模式分为三大类:
- 创建型模式:共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
- 结构型模式:共7种:适配器模式、装饰器模式、代理模式、桥接模式、外观模式、组合模式、享元模式
- 行为型模式:共11种:策略模式、模板方法模式、观察者模式、责任链模式、访问者模式、中介者模式、迭代器模式、命令模式、状态模式、备忘录模式、解释器模式
其实还有两类:并发型模式和线程池模式,用一个图片来整体描述一下:
2、设计模式的六大原则:
(1)开闭原则 (Open Close Principle) :
开闭原则指的是对扩展开放,对修改关闭。在对程序进行扩展的时候,不能去修改原有的代码,想要达到这样的效果,我们就需要使用接口或者抽象类
(2)依赖倒转原则 (Dependence Inversion Principle):
依赖倒置原则是开闭原则的基础,指的是针对接口编程,依赖于抽象而不依赖于具体
(3)里氏替换原则 (Liskov Substitution Principle) :
里氏替换原则是继承与复用的基石,只有当子类可以替换掉基类,且系统的功能不受影响时,基类才能被复用,而子类也能够在基础类上增加新的行为。所以里氏替换原则指的是任何基类可以出现的地方,子类一定可以出现。
里氏替换原则是对 “开闭原则” 的补充,实现 “开闭原则” 的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。
(4)接口隔离原则 (Interface Segregation Principle):
使用多个隔离的接口,比使用单个接口要好,降低接口之间的耦合度与依赖,方便升级和维护方便
(5)迪米特原则 (Demeter Principle):
迪米特原则,也叫最少知道原则,指的是一个类应当尽量减少与其他实体进行相互作用,使得系统功能模块相对独立,降低耦合关系。该原则的初衷是降低类的耦合,虽然可以避免与非直接的类通信,但是要通信,就必然会通过一个“中介”来发生关系,过分的使用迪米特原则,会产生大量的中介和传递类,导致系统复杂度变大,所以采用迪米特法则时要反复权衡,既要做到结构清晰,又要高内聚低耦合。
(6)合成复用原则 (Composite Reuse Principle):
尽量使用组合/聚合的方式,而不是使用继承。
二、Java的23种设计模式:
接下来我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析
1、创建型-工厂方法模式:
工厂方法模式分为三种:
(1)简单工厂模式:
建立一个工厂类,并定义一个接口对实现了同一接口的产品类进行创建。首先看下关系图:
(2)工厂方法模式:
工厂方法模式是对简单工厂模式的改进,简单工厂的缺陷在于不符合“开闭原则”,每次添加新产品类就需要修改工厂类,不利于系统的扩展维护。而工厂方法将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。UML关系图如下:
(3)静态工厂方法模式:
静态工厂模式是将工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
工厂方法模式详情文章:Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)
2、创建型-抽象工厂模式:
抽象工厂模式主要用于创建相关对象的家族。当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象;并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
但该模式的缺点在于添加新的行为时比较麻烦,如果需要添加一个新产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。
UML结构图如下:
抽象工厂模式详情:Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)
3、创建型-建造者模式:
建造者模式将复杂产品的创建步骤分解在在不同的方法中,使得创建过程更加清晰,从而更精确控制复杂对象的产生过程;通过隔离复杂对象的构建与使用,也就是将产品的创建与产品本身分离开来,使得同样的构建过程可以创建不同的对象;并且每个具体建造者都相互独立,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。UML结构图如下:
建造者模式详情:Java设计模式之创建型:建造者模式
4、创建型-单例模式:
单例模式可以确保系统中某个类只有一个实例,该类自行实例化并向整个系统提供这个实例的公共访问点,除了该公共访问点,不能通过其他途径访问该实例。单例模式的优点在于:
- 系统中只存在一个共用的实例对象,无需频繁创建和销毁对象,节约了系统资源,提高系统的性能
- 可以严格控制客户怎么样以及何时访问单例对象。
单例模式的写法有好几种,主要有三种:懒汉式单例、饿汉式单例、登记式单例。
单例模式详情:Java设计模式之创建型:单例模式
5、创建型-原型模式:
原型模式也是用于对象的创建,通过将一个对象作为原型,对其进行复制克隆,产生一个与源对象类似的新对象。UML类图如下:
在 Java 中,原型模式的核心是就是原型类 Prototype,Prototype 类需要具备以下两个条件:
- 实现 Cloneable 接口:
- 重写 Object 类中的 clone() 方法,用于返回对象的拷贝;
Object 类中的 clone() 方法默认是浅拷贝,如果想要深拷贝对象,则需要在 clone() 方法中自定义自己的复制逻辑。
- 浅复制:将一个对象复制后,基本数据类型的变量会重新创建,而引用类型指向的还是原对象所指向的内存地址。
- 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。
使用原型模式进行创建对象不仅简化对象的创建步骤,还比 new 方式创建对象的性能要好的多,因为 Object 类的 clone() 方法是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显;
原型模式详情:Java设计模式之创建型:原型模式
上面我们介绍了5种创建型模式,下面我们就开始介绍下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源,如下图:
6、结构型-适配器模式:
适配器模式主要用于将一个类或者接口转化成客户端希望的格式,使得原本不兼容的类可以在一起工作,将目标类和适配者类解耦;同时也符合“开闭原则”,可以在不修改原代码的基础上增加新的适配器类;将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性,但是缺点在于更换适配器的实现过程比较复杂。
所以,适配器模式比较适合以下场景:
- (1)系统需要使用现有的类,而这些类的接口不符合系统的接口。
- (2)使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。
下面有个非常形象的例子很好地说明了什么是适配器模式:
适配器模式的主要实现有三种:类的适配器模式、对象的适配器模式、接口的适配器模式。三者的使用场景如下:
- 类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
- 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
- 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。
适配器模式详情:Java设计模式之结构型:适配器模式
7、结构型-装饰器模式:
装饰器模式可以动态给对象添加一些额外的职责从而实现功能的拓展,在运行时选择不同的装饰器,从而实现不同的行为;比使用继承更加灵活,通过对不同的装饰类进行排列组合,创造出很多不同行为,得到功能更为强大的对象;符合“开闭原则”,被装饰类与装饰类独立变化,用户可以根据需要增加新的装饰类和被装饰类,在使用时再对其进行组合,原有代码无须改变。装饰器模式的UML结构图如下:
但是装饰器模式也存在缺点,首先会产生很多的小对象,增加了系统的复杂性,第二是排错比较困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
装饰器模式详情:Java设计模式之结构型:装饰器模式
8、结构型-代理模式:
代理模式的设计动机是通过代理对象来访问真实对象,通过建立一个对象代理类,由代理对象控制原对象的引用,从而实现对真实对象的操作。在代理模式中,代理对象主要起到一个中介的作用,用于协调与连接调用者(即客户端)和被调用者(即目标对象),在一定程度上降低了系统的耦合度,同时也保护了目标对象。但缺点是在调用者与被调用者之间增加了代理对象,可能会造成请求的处理速度变慢。UML结构图如下:
代理模式详情:Java设计模式之结构型:代理模式
9、结构型-桥接模式:
桥接模式将系统的抽象部分与实现部分分离解耦,使他们可以独立的变化。为了达到让抽象部分和实现部分独立变化的目的,桥接模式使用组合关系来代替继承关系,抽象部分拥有实现部分的接口对象,从而能够通过这个接口对象来调用具体实现部分的功能。也就是说,桥接模式中的桥接是一个单方向的关系,只能够抽象部分去使用实现部分的对象,而不能反过来。
桥接模式符合“开闭原则”,提高了系统的可拓展性,在两个变化维度中任意扩展一个维度,都不需要修改原来的系统;并且实现细节对客户不透明,可以隐藏实现细节。但是由于聚合关系建立在抽象层,要求开发者针对抽象进行编程,这增加系统的理解和设计难度。桥接模式的UML结构图如下:
就像在Java中我们使用 JDBC 连接数据库时,在各个数据库之间进行切换,基本不需要动太多的代码,原因就是使用了桥接模式,JDBC 提供统一接口,每个数据库提供各自的实现,然后由桥接类创建一个连接数据库的驱动,使用某一个数据库的时候只需要切换一下就行。JDBC 的结构图如下:
在 JDBC 中,桥接模式的实现化角色 (Implementor) 为的 Driver 接口,具体实现化 (Concrete Implementor) 角色对应 MysqlDriver、OracleDriver 和 MariadbDriver,扩展抽象化 (Refined Abstraction) 角色对应 DriverManager,不具有抽象化 (Abstraction) 角色作为扩展抽象化角色的父类。
桥接模式详情:Java设计模式之结构型:桥接模式
10、结构型-外观模式:
外观模式通过对客户端提供一个统一的接口,用于访问子系统中的一群接口。使用外观模式有以下几点好处:
(1)更加易用:使得子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟外观类交互就可以了;
(2)松散耦合:将客户端与子系统解耦,让子系统内部的模块能更容易扩展和维护。
(3)更好的划分访问层次:通过合理使用 Facade,可以更好地划分访问的层次,有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。
但是如果外观模式对子系统类做太多的限制则减少了可变性和灵活性,所以外观模式适用于为复杂子系统提供一个简单接口,提高系统的易用性场景 以及 引入外观模式将子系统与客户端进行解耦,提高子系统的独立性和可移植性。
外观模式的UML结构图如下:
外观模式详情: Java设计模式之结构型:外观模式
11、结构型-组合模式:
组合模式将叶子对象和容器对象进行递归组合,形成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性,能够像处理叶子对象一样来处理组合对象,无需进行区分,从而使用户程序能够与复杂元素的内部结构进行解耦。
组合模式最关键的地方是叶子对象和组合对象实现了相同的抽象构建类,它既可表示叶子对象,也可表示容器对象,客户仅仅需要针对这个抽象构建类进行编程,这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。组合模式的UML结构图如下:
组合模式详情: Java设计模式之结构型:组合模式
12、结构型-享元模式:
享元模式通过共享技术有效地支持细粒度、状态变化小的对象复用,当系统中存在有多个相同的对象,那么只共享一份,不必每个都去实例化一个对象,极大地减少系统中对象的数量,从而节省资源。
享元模式的核心是享元工厂类,享元工厂类维护了一个对象存储池,当客户端需要对象时,首先从享元池中获取,如果享元池中存在对象实例则直接返回,如果享元池中不存在,则创建一个新的享元对象实例返回给用户,并在享元池中保存该新增对象,这点有些单例的意思。
工厂类通常会使用集合类型来保存对象,如 HashMap、Hashtable、Vector 等等,在 Java 中,数据库连接池、线程池等都是用享元模式的应用。
享元模式的UML结构图如下:
Java 中,String 类型就是使用享元模式,String 对象是 final 类型,对象一旦创建就不可改变。而 Java 的字符串常量都是存在字符串常量池中的,JVM 会确保一个字符串常量在常量池中只有一个拷贝。
而且提到共享池,我们也很容易联想到 Java 里面的JDBC连接池,通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!
享元模式详情:Java设计模式之结构型:享元模式
前面我们介绍了7种结构型设计模式,接下来我们介绍一下11种行为型设计模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。先来张图,看看这11中模式的关系:
13、行为型-策略模式:
将类中经常改变或者可能改变的部分提取为作为一个抽象策略接口类,然后在类中包含这个对象的实例,这样类实例在运行时就可以随意调用实现了这个接口的类的行为。
比如定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换,使得算法可独立于使用它的客户而变化,这就是策略模式。UML结构图如下:
策略模式的优点在于可以动态改变对象的行为;但缺点是会产生很多策略类,并且策略模式的决定权在用户,系统只是提供不同算法的实现,所以客户端必须知道所有的策略类,并自行决定使用哪一个策略类;
策略模式适用用于以下几种场景:
- (1)应用程序需要实现特定的功能服务,而该程序有多种实现方式使用,所以需要动态地在几种算法中选择一种
- (2)一个类定义了多种行为算法,并且这些行为在类的操作中以多个条件语句的形式出现,就可以将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。
策略模式详情:Java设计模式之行为型:策略模式
14、行为型-模板方法:
模板方法是基于继承实现的,在抽象父类中声明一个模板方法,并在模板方法中定义算法的执行步骤(即算法骨架)。在模板方法模式中,可以将子类共性的部分放在父类中实现,而特性的部分延迟到子类中实现,只需将特性部分在父类中声明成抽象方法即可,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤,不同的子类可以以不同的方式来实现这些逻辑。
模板方法模式的优点在于符合“开闭原则”,也能够实现代码复用,将不变的行为转移到父类,去除子类中的重复代码。但是缺点是不同的实现都需要定义一个子类,导致类的个数的增加使得系统更加庞大,设计更加抽象。模板方法模式的UML图如下:
模板方法详情:Java设计模式之行为型:模板方法模式
15、行为型-责任链模式:
职责链可以将请求的处理者组织成一条链,并将请求沿着链传递,如果某个处理者能够处理请求则处理,否则将该请求交由上级处理。客户端只需将请求发送到职责链上,无须关注请求的处理细节,通过职责链将请求的发送者和处理者解耦了,这也是职责链的设计动机。
职责链模式可以简化对象间的相互连接,因为客户端和处理者都没有对方明确的信息,同时处理者也不知道职责链中的结构,处理者只需保存一个指向后续者的引用,而不需要保存所有候选者的引用。
另外职责链模式增加了系统的灵活性,我们可以任意增加或更改处理者,甚至更改处理者的顺序,不过有可能会导致一个请求无论如何也得不到处理,因为它可能被放置在链末端。
所以责任链模式有以下几个优点:
- (1)降低耦合度,将请求的发送者和接收者解耦。反映在代码上就是不需要在类中写很多丑陋的 if….else 语句,如果用了职责链,相当于我们面对一个黑箱,只需将请求递交给其中一个处理者,然后让黑箱内部去负责传递就可以了。
- (2)简化了对象,使得对象不需要链的结构。
- (3)增加系统的灵活性,通过改变链内的成员或者调动他们的次序,允许动态地新增或者删除处理者
- (4)增加新的请求处理类很方便。
但是责任链模式也存在一些缺点:
- (1)不能保证请求一定被成功处理
- (2)系统性能将受到一定影响,并且可能会造成循环调用。
- (3)可能不容易观察运行时的特征,而且在进行代码调试时不太方便,有碍于除错。
责任链模式的UML结构图如下:
责任链模式详情:Java设计模式之行为型:责任链模式
16、行为型-观察者模式:
观察者模式又称为 发布-订阅模式,定义了对象之间一对多依赖关系,当目标对象(被观察者)的状态发生改变时,它的所有依赖者(观察者)都会收到通知。一个观察目标可以对应多个观察者,而这些观察者之间没有相互联系,所以能够根据需要增加和删除观察者,使得系统更易于扩展,符合开闭原则;并且观察者模式让目标对象和观察者松耦合,虽然彼此不清楚对方的细节,但依然可以交互,目标对象只知道一个具体的观察者列表,但并不认识任何一个具体的观察者,它只知道他们都有一个共同的接口。
但观察者模式的缺点在于如果存在很多个被观察者的话,那么将需要花费一定时间通知所有的观察者,如果观察者与被观察者之间存在循环依赖的话,那么可能导致系统崩溃,并且观察者模式没有相应的机制让观察者知道被观察对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。观察者模式的UML结构图如下:
观察者模式详情:Java设计模式之行为型:观察者模式
17、行为型-访问者模式:
访问者模式就是一种分离对象数据结构与行为 (基于数据结构的操作) 的方法,通过这种分离,达到为一个被访问者动态添加新的操作而无需做其它修改的效果,使得添加作用于这些数据结构的新操作变得简单,并且不需要改变各数据结构,为不同类型的数据结构提供多种访问操作方式,这样是访问者模式的设计动机。
除了使新增访问操作变得更加简单,也能够在不修改现有类的层次结构下,定义该类层次结构的操作,并将有关元素对象的访问行为集中到一个访问者对象中,而不是分散搞一个个的元素类中。
但访问者模式的缺点在于让增加新的元素类变得困难,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求;
所以访问者模式适用于对象结构中很少改变,但经常需要在此对象结构上定义新的操作的系统,使得算法操作的增加变得简单;或者需要对一个对象结构中进行很多不同并且不相关的操作,并且需要避免让这些操作污染这些对象,也不希望在增加新操作时修改这些类的场景。
访问者模式的UML结构图如下:
从上面的 UML 结构图中我们可以看出,访问者模式主要分为两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,主要用于声明一些操作;一个是元素层次结构,提供了抽象元素和具体元素,主要用于声明 accept 操作;而对象结构 ObjectStructure 作为两者的桥梁,存储了不同类型的对象,以便不同的访问者来访问,相同访问者可以以不同的方式访问不同的元素,所以在访问者模式中增加新的访问者无需修改现有代码,可扩展行强。
在访问者模式使用了双分派技术,所谓双分派技术就是在选择方法的时候,不仅仅要根据消息接收者的运行时区别,还要根据参数的运行时区别。在访问者模式中,客户端将具体状态当做参数传递给具体访问者,这里完成第一次分派,然后具体访问者作为参数的“具体状态”中的方法,同时也将自己this作为参数传递进去,这里就完成了第二次分派。双分派意味着得到的执行操作决定于请求的种类和接受者的类型。
访问者模式详情:Java设计模式之行为型:访问者模式
18、行为型-中介者模式:
中介者模式通过中介者对象来封装一系列的对象交互,将对象间复杂的关系网状结构变成结构简单的以中介者为核心的星形结构,对象间一对多的关联转变为一对一的关联,简化对象间的关系,便于理解;各个对象之间的关系被解耦,每个对象不再和它关联的对象直接发生相互作用,而是通过中介者对象来与关联的对象进行通讯,使得对象可以相对独立地使用,提高了对象的可复用和系统的可扩展性。
在中介者模式中,中介者类处于核心地位,它封装了系统中所有对象类之间的关系,除了简化对象间的关系,还可以对对象间的交互进行进一步的控制。中介者模式的UML结构图如下:
但是,中介者对象封装了对象之间的关联关系,导致中介者对象变得比较庞大复杂,所承担的责任也比较多,维护起来也比较困难,它需要知道每个对象和他们之间的交互细节,如果它出问题,将会导致整个系统都会出问题。
中介者模式详情:Java设计模式之行为型:中介者模式
19、行为型-命令模式:
命令模式的本质是将请求封装成对象,将发出命令与执行命令的责任分开,命令的发送者和接收者完全解耦,发送者只需知道如何发送命令,不需要关心命令是如何实现的,甚至是否执行成功都不需要理会。命令模式的关键在于引入了抽象命令接口,发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。
使用命令模式的优势在于降低了系统的耦合度,而且新命令可以很方便添加到系统中,也容易设计一个组合命令。但缺点在于会导致某些系统有过多的具体命令类,因为针对每一个命令都需要设计一个具体命令类。
命令模式的UML结构图如下:
命令模式详情: Java设计模式之行为型:命令模式
20、行为型-状态模式:
状态模式,就是允许对象在内部状态发生改变时改变它的行为,对象看起来就好像修改了它的类,也就是说以状态为原子来改变它的行为,而不是通过行为来改变状态。
当对象的行为取决于它的属性时,我们称这些属性为状态,那该对象就称为状态对象。对于状态对象而言,它的行为依赖于它的状态,比如要预订房间,只有当该房间空闲时才能预订,想入住该房间也只有当你预订了该房间或者该房间为空闲时。对于这样的一个对象,当它的外部事件产生互动的时候,其内部状态就会发生变化,从而使得他的行为也随之发生变化。
状态模式的UML结构图如下:
从上面的UML结构图我们可以看出状态模式的优点在于:
(1)封装了转换规则,允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块
(2)将所有与状态有关的行为放到一个类中,可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
但是状态模式的缺点在于:
(1)需要在枚举状态之前需要确定状态种类
(2)会导致增加系统类和对象的个数。
(3)对 “开闭原则” 的支持并不友好,新增状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。
所以状态模式适用于:代码中包含大量与对象状态有关的条件语句,以及对象的行为依赖于它的状态,并且可以根据它的状态改变而改变它的相关行为。
状态模式详情:Java设计模式之行为型:状态模式
21、行为型-备忘录模式:
备忘录模式提供了一种恢复状态的机制,在不破坏封装的前提下,捕获对象的某个时刻内部状态,并保存在该对象之外,保证该对象能够恢复到某个历史状态;备忘录模式将保存的细节封装在备忘录中,除了创建它的创建者之外其他对象都不能访问它,并且实现了即使要改变保存的细节也不影响客户端。但是备忘录模式都是多状态和多备份的,会早用较多的内存,消耗资源。备忘录模式的额UML结构图如下:
备忘录模式的核心就是备忘录 Memento,在备忘录中存储的就是原发器 Originator 的部分或者所有的状态信息,而这些状态信息是不能够被其他对象所访问的,也就是说我们是不能使用备忘录之外的对象来存储这些状态信息,如果暴漏了内部状态信息就违反了封装的原则,故备忘录除了原发器外其他对象都不可以访问。所以为了实现备忘录模式的封装,我们需要对备忘录的访问做些控制:
(1)对原发器:可以访问备忘录里的所有信息。
(2)对负责人 caretaker:不可以访问备忘录里面的数据,但是他可以保存备忘录并且可以将备忘录传递给其他对象。
(3)其他对象:不可访问也不可以保存,它只负责接收从负责人那里传递过来的备忘录同时恢复原发器的状态。
备忘录模式详情:Java设计模式之行为型:备忘录模式
22、行为型-迭代器模式:
迭代器模式提供一种访问集合中的各个元素,而不暴露其内部表示的方法。将在元素之间游走的职责交给迭代器,而不是集合对象,从而简化集合容器的实现,让集合容器专注于在它所应该专注的事情上,更加符合单一职责原则,避免在集合容器的抽象接口层中充斥着各种不同的遍历操作。迭代器模式的UML结构图如下:
迭代器模式详情:Java设计模式之行为型:迭代器模式
23、行为型-解释器模式:
解释器模式,就是定义语言的文法,并建立一个解释器来解释该语言中的句子,通过构建解释器,解决某一频繁发生的特定类型问题实例。
解释器模式描述了如何构成一个简单的语言解释器,主要应用在使用面向对象语言开发的编译器中,它描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。
解释器模式中除了能够使用文法规则来定义一个语言,还能通过使用抽象语法树来更加直观表示、更好地地表示一个语言的构成,每一颗抽象语法树对应一个语言实例。抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。 在解释器模式中由于每一种终结符表达式、非终结符表达式都会有一个具体的实例与之相对应,所以系统的扩展性比较好。
解释器模式的UML如下:
解释器模式详情:Java设计模式之行为型:解释器模式
相关推荐阅读:
参考文章:
-
设计模式 - 创建型设计模式 - 原型模式(Java)
2019-02-19 19:51:19请点击http://www.captainbed.net 这是要说的创建型模式的最后一个设计模式了。 原型模式很简单:有一个原型实例,基于这个原型实例产生新的实例,也就是“克隆”了。 Object 类中有一个 clone() 方法,它用于生成... -
Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)
2021-09-12 17:57:40工厂模式将目的将创建对象的具体过程屏蔽隔离起来,从而达到更高的灵活性,工厂模式可以分为三类:简单工厂模式、工厂...当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,保证客户端始终只使用同一个产品族 -
设计模式三大分类——创建模式、结构模式、行为模式
2019-01-18 21:03:32设计模式可以分为创建型、结构型、和行为型模式。 创建型模式对类的实现化过程进行了抽象,能够使软件模块做到与对象的创建和组织无关。 结构型模式描述类和对象之间如何进行有效的组织,以形成良好的软件体系结构... -
设计模式 - 创建型设计模式 - 建造者模式(Java)
2019-08-19 12:00:07好吧,在Java 5之前的版本,使用双重检查锁定创建单例Singleton,记得使用volatile变量。从Java 5开始,使用Enum创建线程安全的Singleton很容易。 Java枚举和单例模式 Java中的枚举单例模式是使用枚举在Jav... -
Java设计模式学习总结(5)——创建型模式之建造者模式
2018-06-19 11:41:20这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。介绍意图:将一个复杂的构建与其表示相分离,使得同样的构建过程... -
设计模式之五大创建型模式(附实例和详解)
2017-11-23 14:07:47Java经典设计模式之五大创建型模式(附实例和详解)一、概况总体来说设计模式分为三大类:(1)创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。(2)结构型模式,共七种:适配器... -
设计模式之创建型模式
2020-08-16 16:02:58创建型模式 一、工厂模式 (一)定义:在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。 (二)应用实例:您需要一辆汽车,可以直接从工厂里面提货,而... -
常见设计模式—单例模式(Singleton)
2020-03-15 20:14:59前言 ...单例模式(Singleton Pattern)是设计模式中最简单的模式之一,属于创建型模式。这种设计模式主要是类的对象只有一个实例,不需要每次new 创造。而我们要做的的就是确保这个对象创建的唯一... -
一张图快速了解23种设计模式
2021-09-10 16:07:41设计模式 设计模式是对被用来在特定场景下解决一般设计问题的类和相互通信的对象的描述。 这是《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented)中对设计模式的... -
面试官:谈谈Spring中用到了哪些设计模式?
2022-03-20 19:13:20设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。 Spring 框架中广泛使用了不同类型的设计模式。 工厂... -
什么是设计模式?程序员如何学好设计模式?
2021-11-30 00:15:58前几天,我给大家介绍了算法和数据结构的基础知识。后来又有小伙伴私信问我:“小灰,你能不能也讲一讲设计模式的相关知识?”没问题!对于程序员来说,设计模式也是必须要掌握的一项核心知识,我今天就... -
Spring中所使用的设计模式
2021-01-14 02:51:09Spring是一个非常优秀的开源框架,项目源码中所使用的设计模式随处可见,这篇文章主要记录一下Spring中常见的设计模式: (1)工厂模式:Spring使用工厂模式,通过BeanFactory和ApplicationContext来创建对象 (2... -
Java设计模式-工厂模式
2021-08-06 09:27:36这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。 简单编写一个类: 1、简单工厂... -
设计模式 - 创建型设计模式小结
2019-03-23 16:31:11创建型模式的作用就是创建对象,说到创建一个对象,最熟悉的就是 new 一个对象,然后 set 相关属性。但是,在很多场景下,我们需要给客户端提供更加友好的创建对象的方式,尤其是那种我们定义了类,但是需要提供给... -
设计模式--创建型模式-单例模式
2021-02-01 18:10:29单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 问题 单例模式同时解决了两个问题, 所以违反了_单一职责原则_: 1. 保证一个类只有一个实例。 2. 为该实例... -
设计模式23模式介绍
2020-01-18 08:20:52一、什么是设计模式 设计模式是一套被反复使用、多数人知晓的、经过分类编写的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式使代码编程真正... -
【Java萌新】面试常问设计模式——工厂模式
2021-06-06 19:17:16本篇总结的是 工厂设计模式,后续会每日更新~ 1、工厂模式简介 ⼯⼚模式介绍:它提供了⼀种创建对象的最佳⽅式,在创建对象时 不会对客户端暴露创建逻辑,并且是通过使⽤⼀个共同的接⼝来指向新创建的对象。 例... -
设计模式(一)设计模式的分类与区别
2020-05-17 11:21:37设计模式的分类、设计模式的原则、设计模式的适用场景、设计模式的区别 -
iOS常见的设计模式:工厂设计模式
2022-03-14 16:34:10iOS常见的设计模式:工厂设计模式 简单工厂模式: 简单工厂模式(Simple Factory Pattern):专门定义一个类(工厂类)来负责创建其他类的实例。可以根据创建方法的参数来返回不同类的实例,被创建的实例通常都具有... -
23 种设计模式详解(全23种)
2019-06-09 00:21:59设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式... -
深入理解设计模式-设计模式分类与关系
2021-12-21 15:35:57文章目录前言一、设计模式分类1.创建型模式,共五种2.结构型模式,共七种3.行为型模式,共十一种4.扩展模式二、设计模式之间的关系结尾 前言 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性... -
设计模式-创建型软件设计模式(一)
2017-07-13 14:30:57主要介绍下面的三个设计模式: (1)工厂模式与抽象工厂模式 (2)生成器模式 (3)单例模式工厂模式工厂模式可以分为简单工厂模式,工厂模式以及抽象工厂模式。简单工厂模式简单工厂模式的特点是仅仅有一个具体... -
Java经典设计模式之五大创建型模式(附实例和详解)
2016-03-06 23:41:09一、概况总体来说设计模式分为三大类:(1)创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。(2)结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、... -
Java设计模式_(创建型)_建造者模式
2017-09-20 16:40:12引用百科 建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。实用范围1 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。2 当构造... -
设计模式课程设计
2020-06-07 22:03:11又要开始写无聊的课程设计,学校是开了课程设计这门课的,但是疫情期间老师选的网课视频的讲解风格不是很好,所以我就自己在bilibili上看视频学习的,具体学习笔记可以看我的《设计模式》专栏