这篇记录下建造者模式、粉饰器模式、门面模式、观察者模式、代理模式和责任链模式~
1、建造者模式
(一)、定义
将一个复杂对象的创建和它的表示分离,使得同样的创建过程可以创建出不同的表示。 通常用于大型复杂对象的创建,并且对于对象的构建有一定的顺序要求。
(二)、结构
比如我们要创建一个Object对象,我们可以将Object对象的属性按照构建的顺序要求,划分成不同的步骤,封装成一个接口。根据不同的建造顺序,编写不同的实现。然后再写一个Director,来封装对象构建过程,提供一个构建的方法,来输出构建的对象。
(三)、代码演示
/**
* @Description: 建造者模式
*/
public interface Builder {
/**
* @description: 构建第一部分属性接口
*
* @param: objectPart1
* @return: void
**/
void buildPart1(String objectPart1);
/**
* @description: 构建第二部分属性接口
*
* @param: objectPart2
* @return: void
**/
void buildPart2(String objectPart2);
/**
* @description: 构建第三部分属性接口
*
* @param: objectPart3
* @return: void
**/
void buildPart3(String objectPart3);
/**
* @description: 构建对象
*
* @return: BuildObject
**/
BuildObject build();
}
/**
* @Description: 构建对象的实现
*/
public class ObjectBuilder implements Builder {
private String objectPart1;
private String objectPart2;
private String objectPart3;
@Override
public void buildPart1(String objectPart1) {
this.objectPart1 = objectPart1;
}
@Override
public void buildPart2(String objectPart2) {
this.objectPart2 = objectPart2;
}
@Override
public void buildPart3(String objectPart3) {
this.objectPart3 = objectPart3;
}
@Override
public BuildObject build() {
return new BuildObject(this.objectPart1, this.objectPart2, this.objectPart3);
}
}
/**
* @Description: 建造者对象
*/
public class BuildObject {
private String objectPart1;
private String objectPart2;
private String objectPart3;
public BuildObject() {
}
public BuildObject(String objectPart1, String objectPart2, String objectPart3) {
this.objectPart1 = objectPart1;
this.objectPart2 = objectPart2;
this.objectPart3 = objectPart3;
}
public String getObjectPart1() {
return objectPart1;
}
public void setObjectPart1(String objectPart1) {
this.objectPart1 = objectPart1;
}
public String getObjectPart2() {
return objectPart2;
}
public void setObjectPart2(String objectPart2) {
this.objectPart2 = objectPart2;
}
public String getObjectPart3() {
return objectPart3;
}
public void setObjectPart3(String objectPart3) {
this.objectPart3 = objectPart3;
}
@Override
public String toString() {
return "BuildObject{" +
"objectPart1='" + objectPart1 + '\'' +
", objectPart2='" + objectPart2 + '\'' +
", objectPart3='" + objectPart3 + '\'' +
'}';
}
}
/**
* @Description: 控制对象的构建
*/
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public BuildObject makeObject(String objectPart1, String objectPart2, String objectPart3){
builder.buildPart1(objectPart1);
builder.buildPart2(objectPart2);
builder.buildPart3(objectPart3);
BuildObject object = builder.build();
return object;
}
}
/**
* @Description: 建造者模式单元测试
*/
public class BuilderTest {
@Test
void test(){
ObjectBuilder objectBuilder = new ObjectBuilder();
Director director = new Director(objectBuilder);
BuildObject object = director.makeObject("1", "2", "3");
System.out.println(object);
}
}
演示的举证的对象比较简单,这里只是做简单的演示,我们还可以将复杂对象的属性多个划分成一部分一起创建~
2、粉饰器模式
(一)、定义
在不改变原有对象的基础上,将功能附加对象上。
(二)、结构
如上图,假如现在要在原有的基础上实现一个新的功能,并且不能修改原来的代码,就可以添加一个装饰器Decorator,它持有原来的接口Component(保留原来的功能),同时实现原来的接口,当编写新功能ConcreteDecorator 时,只需要继承装饰器Decorator,便可在原有的功能基础上添加新的功能。
(三)、代码演示
/**
* @Description: 装饰者举例:原有功能接口
*/
public interface Component {
/**
* @description: 原功能方法
**/
void operation();
}
/**
* @Description: 原有功能实现
*/
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("煮粥....");
}
}
/**
* @Description: 装饰者
*/
public abstract class Decorator implements Component{
protected Component component;
public Decorator(Component component) {
this.component = component;
}
}
/**
* @Description: TODO
* @Author: yjduan
* @CreateTime: 2024-02-05 16:48
*/
public class ConcreteDecorator extends Decorator{
public ConcreteDecorator(Component component) {
super(component);
}
@Override
public void operation() {
System.out.println("煮粥前添加捣碎的皮蛋、肉丝.");
component.operation();
}
}
/**
* @Description: 装饰者模式单元测试
*/
public class DecoratorTest {
@Test
public void test(){
Component component = new ConcreteDecorator(new ConcreteComponent());
component.operation();
}
}
当然,当我们追加功能后,我们还可以利用装饰器继续追加功能~
3、门面模式
(一)、定义
为子系统中一组接口提供一个一致的接口,门面模式定义了一个高层接口,使得子系统中的一组接口更加容易使用。
(二)、结构
门面模式在日常的开发过程会经常使用,也许大家已经使用过多次了。假如在某个系统中有一个工作流,对接了不同的子系统中提供出来的多个方法。我们可以定义一个门面接口,封装这几个子系统中需要用到的方法。把封装后的门面接口,再提供出来使用。这就是门面模式。
(三)、代码演示
/**
* @Description: 子系统1
*/
public class System1 {
/**
* @description: 子系统的方法
**/
public void method(){
System.out.println("子系统1的方法....");
}
}
/**
* @Description: 子系统2
*/
public class System2 {
/**
* @description: 子系统的方法
**/
public void method(){
System.out.println("子系统2的方法....");
}
}
/**
* @Description: 子系统3
*/
public class System3 {
/**
* @description: 子系统的方法
**/
public void method(){
System.out.println("子系统3的方法....");
}
}
/**
* @Description: 门面模式
*/
public interface Facade {
/**
* @description: 门面模式封装的接口
**/
void FacadeMethod();
}
/**
* @Description: 门面模式集成集成实现类
*/
public class ConcreteFacade implements Facade {
private System1 system1 = new System1();
private System2 system2 = new System2();
private System3 system3 = new System3();
@Override
public void FacadeMethod() {
// 子系统1的方法
system1.method();
// 子系统2的方法
system2.method();
// 子系统3的方法
system3.method();
}
}
/**
* @Description: 门面模式单元测试
*/
public class FacadeTest {
@Test
public void test(){
Facade facade = new ConcreteFacade();
facade.FacadeMethod();
}
}
当我们有多个系统去对接时,只需要根据单元测试一样去使用可以了~
4、观察者模式
(一)、定义
定义了对象之间的一对多依赖,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有依赖者都会收到通知并更新。
(二)、结构
主题对象Subject 中实现添加、移出、通知观察者得方法,ConcreteSubject 继承主题对象,并持有目标对象状态属性,当状态修改时,同布更新所有观察者。Observer 接口中定义更新观察者得方法,ConcreteObserver 实现观察者接口,在更新方法中回调ConcreteSubject中得getObserverState() 获取目标对象状态。
(三)、代码演示
/**
* @Description: 主题对象
*/
public class Subject {
// 容器,用来保存关注的观察者对象
private List<Observer> container = new ArrayList<>();
/**
* @description: 添加观察者
*
* @param: [observer]
**/
public void attach(Observer observer){
container.add(observer);
}
/**
* @description: 移除观察者
*
* @param: [observer]
**/
public void detach(Observer observer){
container.remove(observer);
}
/**
* @description: 通知所有的观察者进行更新
**/
protected void notifyObservers(){
for (Observer observer : container) {
observer.update(this);
}
}
}
/**
* @Description: 目标对象(被监测的对象)
*/
public class ConcreteSubject extends Subject {
private String observerState;
public String getObserverState() {
return observerState;
}
/**
* @description: 修改目标对象状态
*
* @param: [observerState]
* @return: void
**/
public void setObserverState(String observerState) {
this.observerState = observerState;
// 状态更新时,通知所有观察者
this.notifyObservers();
}
}
/**
* @Description: 观察者接口,
*/
public interface Observer {
/**
* @description: 更新观察者的接口, 根据目标对象的状态更新
*
* @param subject 目标对象
**/
void update(Subject subject);
}
/**
* @Description: 更新观察者实现
*/
public class ConcreteObserver implements Observer {
@Override
public void update(Subject subject) {
// 获取目标对象的状态,更新观察者的状态
String observerState = ((ConcreteSubject) subject).getObserverState();
System.out.println("根据目标对象的状态:"+ observerState +",更新所有观察者的状态......");
}
}
/**
* @Description: 观察者模式单元测试
*/
public class ObserverTest {
@Test
public void test(){
// 创建两个观察者
Observer task1 = new ConcreteObserver();
Observer task2 = new ConcreteObserver();
// 实例化目标对象
ConcreteSubject subject = new ConcreteSubject();
// 目标对象添加观察者
subject.attach(task1);
subject.attach(task2);
// 修改目标对象状态,触发观察者同布更新
subject.setObserverState("001");
}
}
5、责任链模式
(一)、定义
使多个对象都有机会处理请求,从而避免请求得发送者和接收者之间得耦合关系。将这些对象连成一条链,并沿着这条链传第该请求,直到有一个对象处理它为止。
(二)、结构
用户提交请求后,交给receiver1、receiver2、receiver3 进行处理,根据各自的职责处理请求。当然如果进入对应的处理环节,如果申请条件不符合,也可以直接拒绝,中断申请。
(三)、代码演示
/**
* @Description: 责任链模式
*/
public abstract class Handler {
/** 持有下一个的责任对象*/
protected Handler next = null;
/** 设置下一个处理请求的对象*/
public void setNext(Handler next) {
this.next = next;
}
/**
* @description: 处理请求得方法
*
* @param: days 请假的天数
* @return: boolean 请假审批的结果通知
**/
public abstract boolean handleRequest(Integer days);
}
/**
* @Description: 经理处理请求
*/
public class ManagerHandler extends Handler {
@Override
public boolean handleRequest(Integer days) {
// 部门经理只能审批7天内的请假申请
if(days <= 7) {
System.out.println("部门经理已同意....");
return true;
} else {
// 当前的申请还未处理, 交给直接上级(下一个请求链)进行处理
if(this.next != null) {
return this.next.handleRequest(days);
}
}
return false;
}
}
/**
* @Description: 部门负责人处理请求
*/
public class SectionHeadHandler extends Handler {
@Override
public boolean handleRequest(Integer days) {
// 部门负责人能够处理一个月内的请假申请
if(days <= 30){
System.out.println("部门负责人已同意....");
return true;
} else {
// 如果还未处理
if (null != next){
return this.next.handleRequest(days);
}
}
return false;
}
}
/**
* @Description: 总经理处理请求
*/
public class MasterHandler extends Handler {
@Override
public boolean handleRequest(Integer days) {
// 超过一个月的请假申请总经理处理
if(days > 30){
System.out.println("总经理已同意.....");
return true;
} else {
if(null!=next){
return this.next.handleRequest(days);
}
}
return false;
}
}
/**
* @Description: 责任链模式单元测试
*/
public class ChinaTest {
@Test
public void test(){
// 申明责任链路
Handler managerHandler = new ManagerHandler();
Handler sectionHeadHandler = new SectionHeadHandler();
Handler masterHandler = new MasterHandler();
// 设置请求处理的链路
managerHandler.setNext(sectionHeadHandler);
sectionHeadHandler.setNext(masterHandler);
// 场景测试
Integer days = 15;
boolean result = managerHandler.handleRequest(days);
System.out.println("处理结果:"+ result);
}
}
以上的例子,根据公司请假的流程写了一个简单demo,以供后续参考~
6、代理模式
(一)、定义
为其他对象提供一种代理以控制对这个对象的访问。
(二)、结构
Subject 封装访问对象的接口,realSubject 是实际subject 的实现,proxy 是代理对象。当需要访问realSubject 中已存在数据的属性时,可以直接从realSubject 中直接获取,但如果是realSubject 未加载值的属性,则利用代理对象重新加载realSubject 中不存在的数据。
(三)、代码演示
根据公司组织架构编写一个简单的demo,假如为了节省资源只加载员工表id和员工名称,当需要进一步查询员工信息时,再利用代理加载未加载的属性。
/**
* @Description: 员工属性Api
*/
public interface EmpApi {
public Long getId();
public void setId(Long id);
public String getJobNumber();
public void setJobNumber(String jobNumber);
public String getName();
public void setName(String name);
public Integer getSex();
public void setSex(Integer sex);
public String getAddr();
public void setAddr(String addr);
}
/**
* @Description: 员工属性接口具体的实现(需要被代理的对象)
*/
public class RealEmp implements EmpApi {
private Long id;
private String name;
private String jobNumber;
private Integer sex;
private String addr;
@Override
public Long getId() {
return this.id;
}
@Override
public void setId(Long id) {
this.id = id;
}
@Override
public String getJobNumber() {
return this.jobNumber;
}
@Override
public void setJobNumber(String jobNumber) {
this.jobNumber = jobNumber;
}
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public Integer getSex() {
return this.sex;
}
@Override
public void setSex(Integer sex) {
this.sex = sex;
}
@Override
public String getAddr() {
return this.addr;
}
@Override
public void setAddr(String addr) {
this.addr = addr;
}
}
/**
* @Description: 代理对象,代理具体的员工属性实现
*/
public class EmpProxy implements EmpApi {
/** 持有被代理的目标对象*/
private RealEmp realEmp = null;
/** 标示属性是否需要重新加载*/
private Boolean reloadFlag = false;
public EmpProxy(RealEmp realEmp) {
this.realEmp = realEmp;
}
// 已经记载过的属性,从原数据对象上直接返回
@Override
public Long getId() {
return realEmp.getId();
}
@Override
public void setId(Long id) {
realEmp.setId(id);
}
@Override
public String getName() {
return realEmp.getName();
}
@Override
public void setName(String name) {
realEmp.setName(name);
}
// 未加载过的对象,重新从数据中加载
@Override
public String getJobNumber() {
// 判断是否需要重新加载
if(!this.reloadFlag){
// 数据不存在,重新加载
reload();
this.reloadFlag = true;
}
return realEmp.getJobNumber();
}
@Override
public void setJobNumber(String jobNumber) {
realEmp.setJobNumber(jobNumber);
}
@Override
public Integer getSex() {
// 判断是否需要重新加载
if(!this.reloadFlag){
// 数据不存在,重新加载
reload();
this.reloadFlag = true;
}
return realEmp.getSex();
}
@Override
public void setSex(Integer sex) {
realEmp.setSex(sex);
}
@Override
public String getAddr() {
// 判断是否需要重新加载
if(!this.reloadFlag){
// 数据不存在,重新加载
reload();
this.reloadFlag = true;
}
return realEmp.getAddr();
}
@Override
public void setAddr(String addr) {
realEmp.setAddr(addr);
}
private void reload() {
System.out.println("重新加载不存在的员工数据.....");
this.realEmp.setJobNumber("001");
this.realEmp.setSex(0);
this.realEmp.setAddr("湖北武汉...");
}
}
/**
* @Description: 代理模式单元测试
*/
public class EmpPoxyTest {
@Test
public void test(){
// 首先只加载id和name : 部分加载的时候,需要给代理对象赋值,而不是被代理的目标对象
EmpApi emp = new EmpProxy(new RealEmp());
emp.setId(1L);
emp.setName("张三");
// 访问已加载的数据
System.out.println(emp.getName());
// 访问开始未加载的数据
System.out.println(emp.getJobNumber());
}
}