一、设计模式
1.六大原则
1.【单一原则】:一个类或者一个方法只负责一项职责
2.【里氏替换原则】:子类可以扩展父类的功能,但不能改变原有父类的功能
3.【依赖倒置原则】:面向接口编程,(通过接口作为参数实现应用场景)
- 抽象就是接口或者抽象类,细节就是实现类
- 上层模块不应该依赖下层模块,两者应依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
4.【接口隔离原则】:建立单一接口;(扩展类也是一种接口,一切皆接口)
定义:a.客户端不应该依赖它不需要的接口;b.类之间依赖关系应该建立在最小的接口上
注:接口的设计粒度越小,系统越灵活,但是灵活的同时结构复杂性提高,开发难度也会变大,维护性降低。
5.【迪米特原则】 :最少知道原则,尽量降低类与类之间的耦合,一个对象应该对其他对象有最少的了解
6.【开闭原则】:对扩展开放,对修改闭合。
2.设计模式的分类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uWvDhVYz-1644898667723)(C:\Users\31289\AppData\Roaming\Typora\typora-user-images\image-20220214190409865.png)]
1.单例模式:某个类只能有一个实例,提供一个全局的访问点
2.简单工厂:一个工厂类根据传入的参量决定创建出那一种产品类的实例。
3.工厂方法:定义一个创建对象的接口,让子类决定实例化那个类
4.抽象工厂:创建相关或依赖对象的家族,而无需明确指定具体类。
5.建造者模式:封装一个复杂对象的构建过程,并可以按步骤构造。
6.原型模式:通过复制现有的实例来创建新的实例。
java.lang.Object#clone()
7.适配器模式:将一个类的方法接口转换成客户希望的另外一个接口。
FileInputStream fileInput = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(fileInput);
8.组合模式:将对象组合成树形结构以表示“部分*整体”的层次结构
9.装饰模式:动态的给对象添加新的功能
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
10.代理模式:为其他对象提供一个代理以便控制这个对象的访问。
11.享元(蝇量)模式:通过共享技术来有效的支持大量细粒度的对象。
12.外观模式:对外提供一个统一的方法,来访问子系统中的一群接口。
13.桥接模式:将抽象部分和它的实现部分分离,使他们都可以独立的变化。将抽象与实现解耦。
jdbc中就是使用桥接模式的
14.模板模式:定义一个算法结构,而将一些步骤延迟到子类实现。
java.util.Collections#sort() java.util.AbstractList#indexOf()
15.解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器。
java.util.Pattern.java.text.Format
16.策略模式:定义一系列算法,把他们封装起来,并且使它们可以互相替换。
java.util.Comparator
17.状态模式:允许一个对象在其对象内部状态改变时改变它的行为。
18.观察者模式:对象间的一对多的依赖关系。
javax.servlet.http.HttpSessionAttributeListener
19.备忘录模式:在不破坏封装的前提下,保持对象的内部状态。
20.中介者模式:用一个中介对象来封装一系列的对象交互。
21.命令模式:将命令请求封装为一个对象,使得可以用不同的请求来进行参数化。
22.访问者模式:在不改变数据结构的前提下,增加作用于一组对象元素的新功能
23.责任链模式:将请求的发送者或接收者解耦,使得多个对象都有处理这个请求的机会。
javax.servlet.Filter#doFilter()
24.迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构。
java.util.Iterator
3.UML
UML(Unified Modeling Language)是一种统一建模语言,为面向对象开发系统的产品进行说明、可视化、和编制文档的一种标准语言。下面将对UML的九种图+包图的基本概念进行介绍以及各个图的使用场景。
以往的开发中,特别迷信UML,当然开发过程中一定是设计先行,但是现在的开发讲求灵活性,能用更简单的表示方法进行设计更好,设计的目的是帮我我们更好的理解业务,更好的进行开发。
常见的工具有:powerDesigner Rational Rose proccesson
UML分静态图和动态图两种,其中常用的静态图5种,动态图4种。
常用的静态图:用例图、类图、包图、对象图、部署图
常用的动态图:顺序图,通信图(UML1.x 时称为协作图),状态机图,活动图
(1)类图:
类图(Class diagram)是显示了模型的静态结构,特别是模型中存在的类、类的内部结构以及它们与其他类的关系等。类图不显示暂时性的信息。类图是面向对象建模的主要组成部分。它既用于应用程序的系统分类的一般概念建模,也用于详细建模,将模型转换成编程代码。类图也可用于数据建模。
在UML类图中,常见的有以下几种关系: 泛化(Generalization), 实现(Realization),关联(Association),聚合(Aggregation),组合(Composition),依赖(Dependency)
1、泛化(Generalization)
【泛化关系】:是一种继承关系,表示一般与特殊的关系,它指定了子类如何特化父类的所有特征和行为。例如:老虎是动物的一种,即有老虎的特性也有动物的共性。
【箭头指向】:带三角箭头的实线,箭头指向父类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oFz4UO4z-1644898667725)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\1134451-20170812123014413-2064534630.ac661a9a.png)]
2、实现(Realization)
【实现关系】:是一种类与接口的关系,表示类是接口所有特征和行为的实现
【箭头指向】:带三角箭头的虚线,箭头指向接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2IqKNxZR-1644898667725)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\20120201092741_47.12ca736a.gif)]
3、关联(Association)
【关联关系】:是一种拥有的关系,它使一个类知道另一个类的属性和方法;如:老师与学生,丈夫与妻子关联可以是双向的,也可以是单向的。双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。
【代码体现】:成员变量
【箭头及指向】:带普通箭头的实心线,指向被拥有者
上图中,老师与学生是双向关联,老师有多名学生,学生也可能有多名老师。但学生与某课程间的关系为单向关联,一名学生可能要上多门课程,课程是个抽象的东西它不拥有学生。
下图为自身关联:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Zt3VzCT-1644898667726)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\20120201092741_335.50e5daa8.gif)]
4、聚合(Aggregation)
【聚合关系】:是整体与部分的关系,且部分可以离开整体而单独存在。如车和轮胎是整体和部分的关系,轮胎离开车仍然可以存在。
聚合关系是关联关系的一种,是强的关联关系;关联和聚合在语法上无法区分,必须考察具体的逻辑关系。
【代码体现】:成员变量
【箭头及指向】:带空心菱形的实心线,菱形指向整体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0iPtLYSm-1644898667727)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\20120201092741_681.9be86ead.gif)]
5、组合(Composition)
【组合关系】:是整体与部分的关系,但部分不能离开整体而单独存在。如公司和部门是整体和部分的关系,没有公司就不存在部门。
组合关系是关联关系的一种,是比聚合关系还要强的关系,它要求普通的聚合关系中代表整体的对象负责代表部分的对象的生命周期。
【代码体现】:成员变量
【箭头及指向】:带实心菱形的实线,菱形指向整体
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EXyPD4ZD-1644898667727)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\20120201092741_278.33bbf67a.gif)]
6、依赖(Dependency)
【依赖关系】:是一种使用的关系,即一个类的实现需要另一个类的协助,所以要尽量不使用双向的互相依赖.
【代码表现】:局部变量、方法的参数或者对静态方法的调用
【箭头及指向】:带箭头的虚线,指向被使用者
(2)时序图:
时序图(Sequence Diagram),又名序列图、循序图,是一种UML交互图open in new window。它通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作。它可以表示用例open in new window的行为顺序,当执行一个用例行为时,其中的每条消息对应一个类操作或状态机open in new window中引起转换的触发事件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-64UHsJ1u-1644898667728)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\image-20211102151330465.7152bd4e.png)]
(3)用例图:
是用户与系统交互的最简表示形式,展现了用户open in new window和与他相关的用例open in new window之间的关系。通过用例图,人们可以获知系统不同种类的用户和用例。用例图也经常和其他图表配合使用。
二、工厂设计模式
工厂模式分为简单工厂模式,工厂方法模式和抽象工厂模式
,它们都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽取了出来,目的是降低系统中代码耦合度,并且增强了系统的扩展性。
还有一个很重要的原因,就是对象的创建过程比较复杂,使用工厂模式进行封装,同时可以屏蔽掉对象的复杂的创建过程。
1、简单工厂设计模式
简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。
简单工厂模式包含如下角色:
-
Factory:工厂角色
工厂角色负责实现创建所有实例的内部逻辑
-
Product:抽象产品角色
抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
-
ConcreteProduct:具体产品角色
具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
类图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sDbDSq4T-1644898667728)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\image-20211102153046488.1969a898.png)]
1、定义一个接口
public interface HuaweiPhone {
/**
* 打电话的方法
*/
void call();
}
创建一个实现类
public class Mate50 implements HuaweiPhone {
public void call() {
System.out.println("use a mate50 to make a call.");
}
}
public class P50 implements HuaweiPhone {
public void call() {
System.out.println("use a p50 to make a call.");
}
}
创建一个工厂
public class PhoneFactory {
public static HuaweiPhone getCar(String type){
if("p50".equalsIgnoreCase(type)){
//其中可能有很复杂的操作
return new P50();
}else if("mate50".equalsIgnoreCase(type)){
//其中可能有很复杂的操作
return new Mate50();
}else {
throw new RuntimeException("There are no cell phones of this brand!");
}
}
}
测试
public class Client {
public static void main(String[] args) {
HuaweiPhone p50 = PhoneFactory.getCar("p50");
p50.call();
HuaweiPhone mate50 = PhoneFactory.getCar("mate50");
mate50.call();
}
}
2、工厂方法模式
我们说过java开发中要遵循开闭原则,如果将来有一天我想增加一个新的车,那么必须修改CarFactory,就不太灵活。解决方案是使用工厂方法模式。
工厂方法模式包含如下角色:
- Product:抽象产品
- ConcreteProduct:具体产品
- Factory:抽象工厂
- ConcreteFactory:具体工厂
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SkBOIZQ0-1644898667729)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\image-20211102153137978.7a1b4b82.png)]
我们为每一个车都构建成一个工厂:
先抽象一个工厂接口
public interface Factory {
/**
* 统一的创建方法
* @return
*/
HuaweiPhone create();
}
然后针对每一个产品构建一个工厂方法
public class Mate50Factory implements Factory {
public HuaweiPhone create() {
//中间省略一万行代码
return new Mate50();
}
}
public class P50Factory implements Factory {
public HuaweiPhone create() {
//中间省略一万行代码
return new P50();
}
}
应用场景
public class Client {
public static void main(String[] args) {
Factory benzFactory = new BenzFactory();
Car benz = benzFactory.create();
benz.run();
Factory bmwFactory = new BmwFactory();
Car bmw = bmwFactory.create();
bmw.run();
}
}
好处
此模式中,通过定义一个抽象的核心工厂类,并定义创建产品对象的接口,创建具体产品实例的工作延迟到其工厂子类去完成。这样做的好处是核心类只关注工厂类的接口定义,而具体的产品实例交给具体的工厂子类去创建。当系统需要新增一个产品是,无需修改现有系统代码,只需要添加一个具体产品类和其对应的工厂子类,使系统的扩展性变得很好,符合面向对象编程的开闭原则。
缺点
工厂方法模式虽然扩展性好,但是增加了编码难度,大量增加了类的数量,所以怎么选择还是看实际的需求。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2nCW2LcG-1644898667729)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\image-20211102110530789.f01ac93b.png)]
3、抽象工厂设计模式
抽象工厂模式包含如下角色:
- AbstractFactory:抽象工厂
- ConcreteFactory:具体工厂
- AbstractProduct:抽象产品
- Product:具体产品
抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务、分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-25SWoEyG-1644898667730)(C:\Users\31289\Desktop\MD文件夹\MD图片截图\image-20211102153213009.e85e0a00.png)]
1、定义产品抽象类
电脑产品线
/**
* @author itnanls(微信)
* 我们的服务: 一路陪跑,顺利就业
*/
public abstract class AbstractComputerProduct {
// 生产电脑产品的共享方法
public void sharedMethod(){
System.out.println("这是生产电脑的产品线。");
}
abstract void networking();
}
手机产品线
/**
* @author itnanls(微信)
* 我们的服务: 一路陪跑,顺利就业
*/
public abstract class AbstractPhoneProduct {