一.设计模式的作用
设计模式是软件从业人员长期总结出来用于解决特定问题的通用性框架,它提高了代码的可维护性、可扩展性、可读性以及复用性。
二.设计模式
1.工厂模式
工厂模式提供了创建对象的接口,而无需制定创建对象的具体类,工厂类封装了具体类的创建过程,客户端无需知道具体实现类只需要知道工厂类,通过工厂类来创建具体实现的类。
1).优缺点
优点:
(1).松耦合:无需知道子类具体创建过程,只需要关注工厂类。
(2).可扩展性:扩展性高,如果想增加一个产品,只需要增加子类对应的工厂类即可。
缺点:
每增加一个产品,就需要增加一个具体的类和对应的工厂类,可维护性并不高,增加了代码复杂性。
2).应用场景
使用数据库连接工厂类连接不同的数据库,比如达梦、崖山等
3).类图
4).具体实现过程
(1).创建一个接口
(2).创建实体类
(3).创建工厂类
(4).根据类型调用工厂类连接数据库
2.抽象工厂模式
抽象工厂模式是围绕一个超级工厂创建其他工厂,此超级工厂又称为其他工厂的工厂,抽象工厂模式提供了一个接口,通过此接口及其具体实现类,可以将对象的创建与客户端代码分离,从而实现系统的松耦合。
1).优缺点
优点:
(1).保证产品族一致性:抽象工厂模式创建的产品族类都是同一类产品,客户端使用此族类的产品的时候也都是使用此族类的产品。
(2).实现松耦合:客户端代码只需要通过抽象工厂接口创建产品无需知道产品具体实现代码。
(3).有利于扩展:增加新的产品族类,只需要添加新的具体工厂和产品类即可。
缺点:
每次增加产品族类都要添加一个此族类的工厂代码,还要添加此工厂的具体实现代码,系统和代码复杂性变高。
2).应用场景
比如格力和美的电器都会生产很多产品,空调、洗衣机、冰箱、热水器等,这些都是产品族类。
3).组成
抽象工厂:一般为接口,声明了创建产品对象的方法;
具体工厂:实现了抽象工厂,用于创建产品对象的具体类;
抽象产品:一般为接口或抽象类,声明实现产品的公共方法,具体产品必须要实现此方法;
具体产品:实现了抽象产品;
4).类图
5).具体实现
(1).创建一个接口
(2).创建接口的实体类
(3).创建抽象工厂类
(4).创建抽象工厂类的扩展实现类
(5).创建生成器
(5).使用
3.单例模式
单例模式确保一个类只有一个实例,单例模式还需要提供一个全局访问方法
1).优缺点
优点:
(1).避免一个全局使用的类频繁地创建与销毁
(2).保证了全局状态的一致性
缺点:
(1).过度使用单例可能导致全局状态不可控
2).应用场景
获取打印机去打印图纸,可以使用单例模式去创建打印机;IP访问次数计数等;
3).具体实现
public class Singleton {
//实例私有
private static Singleton instance;
//构造方法私有
private Singleton() {
}
//创建实例的方法公开,如果没创建就创建实例,如果创建了就不在创建
public static Singleton getInstance() {
if (instance == null) {
// 如果实例为空,则创建一个新实例
instance = new Singleton();
}
return instance;
}
}
4.建造者模式
建造者模式提供了一种允许用户逐步设置各种属性来构建对象的方式,很多参数对于一个对象来说可能是可选的,开发者无需传递所有参数去创建对象,对于可选的参数如果用户未传就要去除,所以我们就可以将构建复杂组件的步骤与运用组件构建对象分离,使用builder模式建立。
1).优缺点
优点:
(1).分离构建过程和表示,使得构建过程更加灵活
(2).隐藏具体构建细节,提高封装性
(3).提供代码复用性
缺点:
(1).增加代码复杂性,对于步骤简单的对象没必要使用此模式
2).应用场景
需要生成的对象具有复杂的内部结构,创建者创建对象的步骤和参数过多而且需要更加灵活
3).具体实现
比如一个用户,姓名、电话、性别是必选的,但是住址、年龄、邮箱是可选的,有些用户可能输入年龄,有些用户可能给了地址等;这里通过UserBuilder去实现根据不同的参数创建User对象;
(1).创建User类和UserBuilder类型
public class User {
//名称 必填
private String name;
//性别 必填
private String sex;
//电话 必填
private String phone;
//年龄 可选
private Integer age;
//住址 可选
private String address;
//住址 可选
private String email;
public User(UserBuilder userBuilder) {
this.name = userBuilder.name;
this.sex = userBuilder.sex;
this.phone = userBuilder.phone;
this.age = userBuilder.age;
this.address = userBuilder.address;
this.email = userBuilder.email;
}
public static UserBuilder builder(String name, String sex, String phone){
return new UserBuilder(name,sex,phone);
}
public static class UserBuilder {
//名称
private String name;
//性别
private String sex;
//电话
private String phone;
//年龄
private Integer age;
//住址
private String address;
//住址
private String email;
//构造器
public UserBuilder(String name, String sex, String phone) {
this.name = name;
this.sex = sex;
this.phone = phone;
}
public UserBuilder age(Integer age) {
this.age = age;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public UserBuilder email(String email) {
this.email = email;
return this;
}
public User build(){
return new User(this);
}
}
}
(2).使用UserBuilder创建user
5.原型模式
原型模式通过复制现有对象来创建新对象,也就是拷贝现有的实例对象来创建对象,而不需重头创建对象。
1).优缺点
优点:
(1).提高创建对象的效率,减少创建对象成本
(2).无需知道构造函数内部逻辑,降低了耦合度
缺点:
(1).对于对象内部的引用有循环接口或者对象内部有不支持序列化的引用对象就不支持拷贝
2).应用场景
当类初始化比较复杂、比较耗时耗性能、需要获取权限等的时候需要使用原型模式
3).深拷贝和浅拷贝
(1).浅拷贝:拷贝一个对象后,基本数据类型的变量会重新创建,引用类型指向的还是原对象所指向的
(2).深拷贝:拷贝一个对象后,基本数据类型还有引用对象都是重新创建的,比如clone方法就是深拷贝
4).具体实现
(1).实体类继承Cloneable ,复写clone方法
public class User implements Cloneable {
//名称 必填
private String name;
//性别 必填
private String sex;
//电话 必填
private String phone;
//年龄 可选
private Integer age;
//住址 可选
private String address;
//住址 可选
private String email;
@Override
public User clone() {
try {
return (User) super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
(2).使用
6.适配器模式
通过一个适配器类将一个接口转换成另一个接口,使得两个不兼容的对象能够协同工作,从而消除不兼容问题
1).优缺点
优点:
(1).将不同的系统、库、组件适配在一起,而无需修改太多的代码,提高代码的复用性
(2).拥有更高的灵活性
缺点:
(1).过多的适配器会导致代码混乱降低维护性
2).类图
Mp4PlayerImpl专门用于播放MP4文件,Mp3PlayerImpl专门用于播放MP3,如果Mp4PlayerImpl想播放MP3文件那么就需要一个适配器Mp4PlayerAdapter去适配Mp3PlayerImpl的接口,去代理播放MP3文件。
3).具体实现
(1).实现MP4播放功能
(2).实现MP3播放功能
(3).实现MP4的适配器
(4).使用
7.策略模式
根据条件(比如操作类型)而选择不同的行为或者算法,这就是策略模式,如果将不同的行为代码硬编写在一起会非常臃肿同时也不利于拓展。
1).优缺点
优点:
(1).算法可以根据条件选择
(2).利于拓展
(3).可以将公共方法抽出放在父类中,提高代码复用性
缺点:
(1).每个行为或者算法都要有一个类,这导致类的增加,导致测量膨胀
(2).所有策略类都要对外暴露,不太安全
2).应用场景
需要根据条件去选择不同的行为,比如高速公路显示屏可以根据不同指令选择播放语音、播放文字、还是点亮警报灯
3).类图
抽象类OperateHander有三个子类LineOperateHander、MusicOperateHander、PlayOperateHander,通过适配器器OperateManager根据类型去判断使用不同的Hander
4).具体实现
(1).编写Hander
(2).编写枚举
@Getter
@AllArgsConstructor
public enum OperateType {
LINE_OPERATE("line", "lineOperateHander"),
MUSIC_OPERATE("music", "musicOperateHander"),
PLAY_OPERATE("play", "playOperateHander"),
;
private final String type;
private final String handler;
public static OperateType getByType(String type) {
OperateType[] types = values();
for (OperateType syncType : types) {
if (syncType.getType().equals(type)) {
return syncType;
}
}
return null;
}
}
(3).编写适配器
8.模版模式
模板方法模式通过定义一个抽象的父类,其中包含了流程中公共的行为,子类去实现流程中非公共的行为,这样就可以保证核心流程保持不变,同时增加了代码的复用性
1).优缺点
优点:
(1).增加代码复用性
(2).所有子类共享父类的代码,保证代码一致性
(3).利于维护
缺点:
(1).每一个非公共的行为都要增加一个子类,增加了子类的数量
2).应用场景
请假的流程和请病假的流程基本一致,都需要发起流程、主管审批、经理审批,但是请假发起流程的时候需要输入请假理由、请假天数等,但是请病假需要申请理由、请假天数、还需要医院症断书等,我们将公共部分的流程(发起、主管审批、经理审批)抽到父类,具体的差别子类去实现
3).类图
4).具体实现
(1).编写模版代码
(2).编写请假代码
(3).编写请病假代码
9.观察者模式
观察者模式定义了一种一对多的依赖关系,一个被观察者(主题)对应多个观察者,被观察者发生改变时候会通知所有观察者。观察者实现了与观察者之间的解耦。
1).优缺点
优点:
(1).观察者和被观察者是解耦合的。
(2).主题状态改变时会自动通知观察者,减少手动维护通知的工作
缺点:
(1).异步操作可能无法保证顺序一致性
(2).可能存在循环依赖的问题
2).业务场景
老师发布放假信息,所有的学生都会收到通知
3).具体实现
(1).编写观察者代码
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/7e42afad03f542cda88f0c00d3fc71b9.png)
(2).编写主题代码