适配器模式,策略模式,责任链模式
文章目录
1,课程回顾
2,本章重点
1), 适配器模式
2), 策略模式
3), 责任链模式
3,具体内容
3.1 适配器模式(Adaptor Pattern)
3.1.1 定义
转换一个类的接口为客户端所需要的接口,将两个不兼容的类纠合在一起使用,这个转换的类就是适配器类。它属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份.它的宗旨就是,保留现有类所提供的服务,向客户提供接口,以满足客户的期望。
3.1.2 生活例子(百度百科)
中国的电源电压为 220V ,而日本的电源电压 110V ,在国内使用日本原装电器时,就必须有一个电源适配器将 220V 的电压适配至 110V
一般家庭中电源插座有的是两个孔(两项式)的,也有三个孔(三项式)的。很多时候我们可能更多地使用三个引脚的插头,但是那种两孔的插座就不能满足我们的需求,此时我们一般会买一个拖线板,该拖线板的插头是是两脚插头,这样就可以插入原先的两孔插座,同时拖线板上带有很多两孔、三孔的插座!这样不仅可以扩容,更主要的是将两孔的插座转变为三孔的插座。
3.1.3 适配器的角色
目标(Target)角色:期待得到的接口。
源(Adaptee)角色: 需要适配的接口。
适配器(Adaptor)角色:适配器类是本模式的核心,在Target目标角色与Adaptee源角色之间提供一种过渡。适配器把Adaptee源接口转换成Target目标接口。显然,这一角色不可以是接口,而必须是具体类。
3.1.3 适配器模式分类
类适配器模式:适配器继承源角色类(继承),实现目标接口。
对象适配器模式:适配器容纳一个它包裹的类的实例(依赖),实现目标接口。
区别: 不同之处于两者在包装Adaptee源角色时,前者(类适配)包装的是Adaptee类(因为它同时从Target与Adaptee继承而来,可想而知,类适配的Adatper必须是一个具体类,而Target只能是一个接口),后者(对象适配)则直接包裹了一个源Adaptee的实例。
3.1.4 实例语法
源(Adapee)角色
package com.aaa.dp.adapter.demo4;
/**
* @ fileName:Adaptee
* @ description: 源(Adapee)角色
* @ author:zhz
* @ createTime:2020/3/22 14:55
* @ version:1.0.0
*/
public class Adaptee {
public void specialRequest(){
System.out.println("Called SpecificRequest() in Adaptee ");
}
}
目标(Target)角色
package com.aaa.dp.adapter.demo4;
/**
* @ fileName:Target
* @ description:目标(Target)角色
* @ author:zhz
* @ createTime:2020/3/22 14:54
*/
public interface Target {
void request();
}
适配器(Adaper)角色 类适配器
package com.aaa.dp.adapter.demo4;
/**
* @ fileName:Adapter
* @ description:适配器(Adaper)角色 类适配器
* @ author:zhz
* @ createTime:2020/3/22 14:57
* @ version:1.0.0
*/
public class Adapter extends Adaptee implements Target{
@Override
public void request() {
this.specialRequest();
System.out.println("模拟转换。。。");
}
}
适配器(Adaper)角色 对象适配器模式
package com.aaa.dp.adapter.demo4;
/**
* @ fileName:Adapter2
* @ description:适配器(Adaper)角色 对象适配器模式
* @ author:zhz
* @ createTime:2020/3/22 14:59
* @ version:1.0.0
*/
public class Adapter2 implements Target {
Adaptee adaptee = new Adaptee();
@Override
public void request() {
adaptee.specialRequest();
System.out.println("模拟转换");
}
}
3.1.5 真正实例
源角色
package com.aaa.dp.adaptor;
/**
* @ fileName:AdapteeHomePower
* @ description: 源角色类 提供220v电压输出
* @ author:zhz
* @ createTime:2021/12/27 14:36
* @ version:1.0.0
*/
public class AdapteeHomePower {
/**
* 提供220v交流电
* @return
*/
public int support220ACPower(){
return 220;
}
}
目标角色
package com.aaa.dp.adaptor;
/**
* @ fileName:TargetElectronicProductPower
* @ description:
* @ author:zhz
* @ createTime:2021/12/27 14:39
* @ version:1.0.0
*/
public interface TargetElectronicProductPower {
/**
* 充电电源
* @param type 1,苹果手机 2,安卓手机 3,平板 4, 其他产品不支持
*/
void chargePower(int type);
}
适配器角色(类模式)
package com.aaa.dp.adaptor;
/**
* @ fileName:ClassAdaptor
* @ description: 类适配器 : 是源角色的子类 并且实现目标接口
* @ author:zhz
* @ createTime:2021/12/27 14:41
* @ version:1.0.0
*/
public class ClassAdaptor extends AdapteeHomePower implements TargetElectronicProductPower{
@Override
public void chargePower(int type) {
//通过继承获取源角色的方法
int ac220V = this.support220ACPower();
//模拟转换,实例开发根据不同业务做处理
int dc5V =ac220V/44;
if(type==1){
System.out.println("当前设备为苹果手机,输出电压为"+dc5V+"v,充电电流1A,输出功率:"+dc5V*1+"w");
}else if(type==2){
System.out.println("当前设备为安卓手机,输出电压为"+dc5V+"v,充电电流2A,输出功率:"+dc5V*2+"w");
}else if(type==3){
System.out.println("当前设备为平板,输出电压为"+dc5V+"v,充电电流2.4A,输出功率:"+dc5V*2.4+"w");
}else {
System.out.println("不支持当前设备");
}
}
}
测试
package com.aaa.dp.adaptor;
/**
* @ fileName:Test
* @ description:
* @ author:zhz
* @ createTime:2021/12/27 14:47
* @ version:1.0.0
*/
public class Test {
public static void main(String[] args) {
ClassAdaptor classAdaptor =new ClassAdaptor();
classAdaptor.chargePower(5);
System.out.println("------------------------------");
ObjectAdaptor objectAdaptor =new ObjectAdaptor();
objectAdaptor.chargePower(1);
}
}
适配器角色(对象模式)
package com.aaa.dp.adaptor;
/**
* @ fileName:ObjectAdaptor
* @ description:
* @ author:zhz
* @ createTime:2021/12/27 14:49
* @ version:1.0.0
*/
public class ObjectAdaptor implements TargetElectronicProductPower {
//依赖
private AdapteeHomePower adapteeHomePower =new AdapteeHomePower();
@Override
public void chargePower(int type) {
//通过继承获取源角色的方法
int ac220V = adapteeHomePower.support220ACPower();
//模拟转换,实例开发根据不同业务做处理
int dc5V =ac220V/44;
if(type==1){
System.out.println("当前设备为苹果手机,输出电压为"+dc5V+"v,充电电流1A,输出功率:"+dc5V*1+"w");
}else if(type==2){
System.out.println("当前设备为安卓手机,输出电压为"+dc5V+"v,充电电流2A,输出功率:"+dc5V*2+"w");
}else if(type==3){
System.out.println("当前设备为平板,输出电压为"+dc5V+"v,充电电流2.4A,输出功率:"+dc5V*2.4+"w");
}else {
System.out.println("不支持当前设备");
}
}
}
3.2策略模式(Strategy Pattern)
3.2.1 定义:
定义了一组算法/业务方法,将每个算法/业务方法都封装起来,并且使它们之间可以互换
3.2.2 现实例子:
我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。
商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的
3.2.3 使用场景:
1,如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
2,一个系统需要动态地在几种算法中选择一种。
3,如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
4,不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,提高算法的保密性与安全性。
3.2.4 实现:
策略接口
package com.aaa.dp.strategy1;
/**
* @ fileName:GameStrategy
* @ description:策略接口
* @ author:zhz
* @ createTime:2020/3/23 10:41
*/
public interface GameStrategy {
/**
* 角色选择
* @param heroName 英雄名称
* @param skillCombo 技能连招
*/
void heroChoice(String heroName,String skillCombo);
}
策略实现类(不同算法或者策略)
package com.aaa.dp.strategy1;
/**
* @ fileName:MasterHeros
* @ description:策略选项
* @ author:zhz
* @ createTime:2020/3/23 10:42
* @ version:1.0.0
*/
public class MasterHeros implements GameStrategy {
@Override
public void heroChoice(String heroName, String skillCombo) {
System.out.println("我是法师"+heroName+"擅长AP,连招技能为"+skillCombo);
}
}
package com.aaa.dp.strategy1;
/**
* @ fileName:FightWildHeros
* @ description:策略选项
* @ author:zhz
* @ createTime:2020/3/23 10:42
* @ version:1.0.0
*/
public class FightWildHeros implements GameStrategy{
@Override
public void heroChoice(String heroName, String skillCombo) {
System.out.println("我是打野"+heroName+"擅长刺杀,连招技能为"+skillCombo);
}
}
package com.aaa.dp.strategy1;
/**
* @ fileName:TankHeros
* @ description:策略选项
* @ author:zhz
* @ createTime:2020/3/23 10:42
* @ version:1.0.0
*/
public class ShooterHeros implements GameStrategy{
@Override
public void heroChoice(String heroName, String skillCombo) {
System.out.println("我是射手"+heroName+"擅长AD,连招技能为"+skillCombo);
}
}
package com.aaa.dp.strategy1;
/**
* @ fileName:TankHeros
* @ description:策略选项
* @ author:zhz
* @ createTime:2020/3/23 10:42
* @ version:1.0.0
*/
public class TankHeros implements GameStrategy{
@Override
public void heroChoice(String heroName, String skillCombo) {
System.out.println("我是坦克"+heroName+"擅长做肉盾,连招技能为"+skillCombo);
}
}
package com.aaa.dp.strategy1;
策略模式选择类
/**
* @ fileName:Context
* @ description:策略选择上下文对象
* @ author:zhz
* @ createTime:2020/3/23 10:49
* @ version:1.0.0
*/
public class Context {
private GameStrategy gameStrategy;
public Context(GameStrategy gameStrategy){
this.gameStrategy = gameStrategy;
}
/**
* 执行选择英雄,使用不同策略
* @param heroName
* @param skillCombo
*/
public void executeGameStrategy(String heroName,String skillCombo){
gameStrategy.heroChoice(heroName,skillCombo);
}
}
测试:
package com.aaa.dp.strategy1;
/**
* @ fileName:StrategyTest
* @ description:测试
* @ author:zhz
* @ createTime:2020/3/23 10:51
* @ version:1.0.0
*/
public class StrategyTest {
public static void main(String[] args) {
//选择法师
Context context1 =new Context(new MasterHeros());
context1.executeGameStrategy("诸葛亮","2123AA");
//选择坦克
Context context2 =new Context(new TankHeros());
context2.executeGameStrategy("程咬金","12A3A2A");
//选择射手
Context context3 =new Context(new ShooterHeros());
context3.executeGameStrategy("小鲁班","3A1A2AA");
//选择打野
Context context4 =new Context(new FightWildHeros());
context4.executeGameStrategy("娜可露露","313A2A");
}
}
3.2.5 总结
- 优点
策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基- 础上选 择算法或行为,也可以灵活地增加新的算法或行为。
策略模式提供了管理相关的算法族的办法。
使用策略模式可以避免使用多重条件转移语句。 - 缺点
策略类会增多。
所有策略类都需要对外暴露。(客户端必须知道所有的策略类,并自行决定使用哪一个策略类。)
3.3 职责链(Chain of Responsibility Pattern)
3.3.1 定义
责任链模式是一种设计模式,在责任链模式里, 为了避免请求的发送者和接受者耦合在一起,于是将所有请求的处理者通过一个对象的引用记住其下家而连接起来形成一条链。并沿着这条链传递该请求,直到有一个对象处理它为止。
3.3.2 现实例子
请假流程(员工提交请假申请 班长审批(3天) 主管审批(7天) 主任审批(30天) 副总审批(180天)),采购流程(采购人填写采购单,采购主管审批,总监审批,总经理审批,财务审批,首付款,采购,验货,入库,付尾款),报销流程(填写报销申请,粘贴附件,本部门负责人复核,财务复核,总经理审批,出纳付款)等等。。。
3.3.3 实例
流程数据载体
package com.aaa.dp.cr1;
/**
* @ fileName:LeaveApply
* @ description:
* @ author:zhz
* @ createTime:2020/8/13 11:01
* @ version:1.0.0
*/
public class LeaveApply {
private String realName;
private int leaveDays;
public LeaveApply(String realName, int leaveDays) {
this.realName = realName;
this.leaveDays = leaveDays;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public int getLeaveDays() {
return leaveDays;
}
public void setLeaveDays(int leaveDays) {
this.leaveDays = leaveDays;
}
}
抽象责任处理类
package com.aaa.dp.cr1;
/**
* @ fileName:AbstractLeaveHandler
* @ description:
* @ author:zhz
* @ createTime:2020/8/13 11:05
* @ version:1.0.0
*/
public abstract class AbstractLeaveHandler {
//班长审批
protected final int LEVEL1 = 3;
//主管审批
protected final int LEVEL2 = 7;
//主任审批
protected final int LEVEL3 =30;
//副总审批
protected final int LEVEL4 = 180;
//处理人名称
protected String handlerName;
//下一个处理环节
protected AbstractLeaveHandler nextHandler;
/**
* 设置下一个处理环节
* @param nextHandler
*/
public void setNextHandler(AbstractLeaveHandler nextHandler) {
this.nextHandler = nextHandler;
}
/**
* 处理请假请求
* @param leaveApply
*/
public abstract void handlerApply(LeaveApply leaveApply);
}
班长处理环节类
package com.aaa.dp.cr1;
/**
* @ fileName:MonitorHandler
* @ description: 班长处理
* @ author:zhz
* @ createTime:2020/8/13 11:11
* @ version:1.0.0
*/
public class MonitorHandler extends AbstractLeaveHandler{
/**
* 构造赋值给当前处理人
* @param handlerName
*/
public MonitorHandler(String handlerName) {
this.handlerName =handlerName;
}
@Override
public void handlerApply(LeaveApply leaveApply) {
//判断在不在班长处理范围之内
if(leaveApply.getLeaveDays()<=LEVEL1){
System.out.println("班长:" + handlerName + "已经处理,流程结束。");
return;
}
//判断下一个环节是否为空,不为空,下一个处理
if(this.nextHandler!=null){
this.nextHandler.handlerApply(leaveApply);
}else {
System.out.println("请假请求被拒绝!");
}
}
}
主管处理环节类
package com.aaa.dp.cr1;
/**
* @ fileName:ManagerHandler
* @ description:主管处理
* @ author:zhz
* @ createTime:2020/8/13 11:11
* @ version:1.0.0
*/
public class ManagerHandler extends AbstractLeaveHandler{
/**
* 构造赋值给当前处理人
* @param handlerName
*/
public ManagerHandler(String handlerName) {
this.handlerName =handlerName;
}
@Override
public void handlerApply(LeaveApply leaveApply) {
//判断在不在班长处理范围之内
if(leaveApply.getLeaveDays()>LEVEL1&&leaveApply.getLeaveDays()<=LEVEL2){
System.out.println("主管:" + handlerName + "已经处理,流程结束。");
return;
}
//判断下一个环节是否为空,不为空,下一个处理
if(this.nextHandler!=null){
this.nextHandler.handlerApply(leaveApply);
}else {
System.out.println("请假请求被拒绝!");
}
}
}
主任处理环节类
package com.aaa.dp.cr1;
/**
* @ fileName:DirectorHandler
* @ description:主任处理
* @ author:zhz
* @ createTime:2020/8/13 11:11
* @ version:1.0.0
*/
public class DirectorHandler extends AbstractLeaveHandler{
/**
* 构造赋值给当前处理人
* @param handlerName
*/
public DirectorHandler(String handlerName) {
this.handlerName =handlerName;
}
@Override
public void handlerApply(LeaveApply leaveApply) {
//判断在不在班长处理范围之内
if(leaveApply.getLeaveDays()>LEVEL2&&leaveApply.getLeaveDays()<=LEVEL3){
System.out.println("主任:" + handlerName + "已经处理,流程结束。");
return;
}
//判断下一个环节是否为空,不为空,下一个处理
if(this.nextHandler!=null){
this.nextHandler.handlerApply(leaveApply);
}else {
System.out.println("请假请求被拒绝!");
}
}
}
副总处理环节类
package com.aaa.dp.cr1;
/**
* @ fileName:VicePresident
* @ description:
* @ author:zhz
* @ createTime:2020/8/13 11:11
* @ version:1.0.0
*/
public class VicePresidentHandler extends AbstractLeaveHandler{
/**
* 构造赋值给当前处理人
* @param handlerName
*/
public VicePresidentHandler(String handlerName) {
this.handlerName =handlerName;
}
@Override
public void handlerApply(LeaveApply leaveApply) {
//判断在不在班长处理范围之内
if(leaveApply.getLeaveDays()>LEVEL3&&leaveApply.getLeaveDays()<=LEVEL4){
System.out.println("副总:" + handlerName + "已经处理,流程结束。");
return;
}
//判断下一个环节是否为空,不为空,下一个处理
if(this.nextHandler!=null){
this.nextHandler.handlerApply(leaveApply);
}else {
System.out.println("请假请求被拒绝!");
}
}
}
测试类
package com.aaa.dp.cr1;
/**
* @ fileName:ResponsibilityTest
* @ description:
* @ author:zhz
* @ createTime:2020/8/13 11:21
* @ version:1.0.0
*/
public class ResponsibilityTest {
public static void main(String[] args) {
//实例化请假申请
LeaveApply leaveApply = new LeaveApply("张三",190);
//实例化责任链
MonitorHandler monitorHandler =new MonitorHandler("赵班长");
ManagerHandler managerHandler = new ManagerHandler("钱主管");
DirectorHandler directorHandler =new DirectorHandler("孙主任");
VicePresidentHandler vicePresidentHandler =new VicePresidentHandler("李副总");
//设置下一个环节
monitorHandler.setNextHandler(managerHandler);
managerHandler.setNextHandler(directorHandler);
directorHandler.setNextHandler(vicePresidentHandler);
//处理请求
monitorHandler.handlerApply(leaveApply);
}
}
3.3.4 总结
责任链主要重在责任分离处理,让各个节点各司其职。
责任链上的各个节点都有机会处理事务,但是也可能不会受理请求。
责任链比较长,调试时可能会比较麻烦。
责任链一般用于处理流程节点之类的实际业务场景中。
Spring拦截器链、servlet过滤器链等都采用了责任链设计模式。
更多推荐



所有评论(0)