携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情
前言
关于设计模式,相信大家都不陌生,无论是在日常的开发过程中,还是在面试的过程中面试官的提问,或多或少都会涉及到设计模式,通常我们使用设计模式开发,可以使我们的代码结构更加清晰、避免重复造轮子、也可以使代码更加简洁,所以在开发中我们需要尽量使用设计模式来开发。
关于Spring的设计模式,在网上搜了很多,其实大家讲的都差不多,这里我主要是结合项目开发,将常用的一些设计模式运用到项目中使用,让我们能了解设计模式的同时,也能很方便的运用在日常开发中。
工厂设计模式
在Spring中,我们拿到IOC容器无非有三种方式,那就是使用ApplicationContext接口下的三个实现类:ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext ApplicationContextAware接口是用来获取框架自动初始化的Ioc容器对象的。
通过枚举值不同来加载不同的Bean,这就是工厂模式。
Example:
public class ResourceProviderFactory implements ApplicationContextAware {
private ApplicationContext applicationContext;
public ResourceProvider getProviderByResourceType(CfgResourceTypeDTO resourceType) {
if (resourceType == null) {
return null;
}
ResourceProvider resourceProvider = null;
if (StringUtils.equals("ENUM", resourceType.getResCate())) {
resourceProvider = applicationContext.getBean("enumResourceProvider", ResourceProvider.class);
} else if (StringUtils.equals("student", resourceType.getResCate())) {
resourceProvider = applicationContext.getBean("studentResourceProvider", ResourceProvider.class);
}else if(StringUtils.equals("teacher", resourceType.getResCate())) {
resourceProvider = applicationContext.getBean("teacherResourceProvider", ResourceProvider.class);
}else if (StringUtils.equals("class", resourceType.getResCate())) {
resourceProvider = applicationContext.getBean(classResourceProvider, ResourceProvider.class);
}
return resourceProvider;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
模版设计模式
模版模式就是类似于我们定义了一个基本的机构,子类可以不去改变这个结构的情况下, 去针对于某些业务场景进行特定的实现。这样可以使我们业务得到拓展的情况下,又不会去改变原来的结构。
public abstract class TemplateTest {
//定义模版方法
public void templateMethod(){
submit();
save();
find();
}
//模版类提交方法
protected void submit(){
}
//被子类重写的方法
protected abstract void save();
protected abstract void find();
//子类实现
class TemplateImpl extends TemplateTest{
//子类派生提交方法
@Override
protected void submit() {
}
@Override
protected void save() {
}
@Override
protected void find() {
}
}
}
观察者设计模式
观察者模式(Observer),其实主要是来定义一对多的关系,通过发布者发布一个状态发生改变,其他的观察者通过订阅消息,都能接收到通知发生改变,在这个过程中还可以通过加入更多的观察者来达到可扩展。 设计主要包含这几个角色,观察者接口、不同岗位的观察者、被观察者接口、配置观察者。 我拿具体的一个审批业务场景来设计观察者模式,需要审批的业务单在公共池,如果订单被领导审批。状态发生改变,需要不同的业务员去观察业务单的状态,同时也可以新增加新的业务审批员。
首选定义观察者接口
public interface Observer {
//观察者修改方法
void update(String message);
}
定义主题接口
public interface Station {
//添加审批业务员
void registerObserver(Observer o);
//删除审批业务员
void removeObserver(Observer o);
//通知审批业务员
void notifyObserver();
}
推送消息主题
public class ManagerServer implements Station{
private List<Observer> list;
private String msg;
public ManagerServer() {
list = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if (!list.isEmpty()) {
list.remove(o);
}
}
@Override
public void notifyObserver() {
for (int i = 0; i <list.size() ; i++) {
Observer observer =list.get(i);
observer.update(msg);
}
}
public void noticMessage(String msg){
this.msg = msg;
System.out.println("业务数据发生更新: " + msg);
// 当观察者调用noticMessage方法时,会调用notifyObserver通知其他观察者更新消息
notifyObserver();
}
}
具体观察者实现
public class ObserverImpl implements Observer{
private String name;
public ObserverImpl(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name+"收到推送消息"+message);
}
}
测试方法
public class ObserverTest {
public static void main(String[] args) {
ManagerServer managerServer = new ManagerServer();
//加入
ObserverImpl Lxlxxx = new ObserverImpl("Lxlxxx");
ObserverImpl Lxlxxx2 = new ObserverImpl("Lxlxxx2");
//注册需要监听的观察者
managerServer.registerObserver(Lxlxxx);
managerServer.registerObserver(Lxlxxx2);
managerServer.noticMessage("业务单的审批状态已发生改变");
System.out.println("----------------------------------------------");
//删除Lxlxxx2业务员
managerServer.removeObserver(Lxlxxx2);
managerServer.noticMessage("业务单的审批状态再次发生改变");
}
}
测试结果 业务单子状态发生改变后会通知其他注册业务员,观察者业务员会收到通知单子状态发生改变,同时如果去remove业务员,那么下次发送业务单子发生改变时,就无法接受到订单状态通知了。
适配器设计模式
Spring MVC 的HandlerAdapter就是适配处理器,主要是用于适配DispatcherServlet通过HandlerMapping的映射到对应的Handler,通过HandlerAdapter适配器来适配不同的Controller
Example:
支付方法
public class Payment {
public void offline() {
System./out/.println(“目前付款模式只支持线下付款~~~”);
}
}
多种支付方法
public interface PaymentType {
public void offline();
//微信支付
public void weixin();
//支付宝支付
public void zhifubao();
//银行转账
public void bankTransfer();
}
通过Adapter适配器使Payment支持多种付款模式
public class Adapter extends Payment implements PaymentType{
@Override
public void weixin() {
System./out/.println(“使用微信线上付款”);
}
@Override
public void zhifubao() {
System./out/.println(“使用支付宝线上付款”);
}
@Override
public void bankTransfer() {
System./out/.println(“使用银行转账付款”);
}
}
测试方法:
public class AdapterTest {
public static void main(String[] args) {
PaymentType paymentType = new Adapter();
paymentType.offline();
paymentType.weixin();
paymentType.zhifubao();
paymentType.bankTransfer();
}
}
以上是对类的适配,需要继承适配的类,当然还有对象适配器,就不用去继承类了,直接在适配器里面去实例化对象。
对象适配模式
public class ObjectAdapter implements PaymentType{
private Payment payment;
public ObjectAdapter(Payment payment) {
super();
this.payment = payment;
}
@Override
public void offline() {
System.out.println("线下现金付款");
}
@Override
public void weixin() {
System.out.println("使用微信线上付款");
}
@Override
public void zhifubao() {
System.out.println("使用支付宝线上付款");
}
@Override
public void bankTransfer() {
System.out.println("使用银行转账付款");
}
}
测试方法:
public class AdapterTest {
public static void main(String[] args) {
PaymentType paymentType = new ObjectAdapter(new Payment());
paymentType.offline();
paymentType.weixin();
paymentType.zhifubao();
paymentType.bankTransfer();
}
}
策略(Strategy)设计模式
策略模式和适配器模式大同小异,从类型上看,一个是结构模式,一个是行为模式。 策略模式:通过环境类把所有的算法统一封装起来,统一提供一个接口给客户端用,算法的新增和修改都比较灵活。 适配器模式:把两个或多个不兼容的接口,通过Adapte适配器类,让它们都彼此兼容,都可以进行调用。
Example 下面通过业务场景说下策略模式,保费计算,子女付费50%,父母付费80%。
策略方法
public interface Strategy {
//保费计算基本方法
Double premiumFormula(Double cost);
}
子女保费计算
public class ChildrenStrategy implements Strategy {
@Override
public Double premiumFormula(Double cost) {
//子女费用减半
cost =cost*0.5;
return cost;
}
}
父母保费计算
public class ParentStrategy implements Strategy{
@Override
public Double premiumFormula(Double cost) {
//父母八折
cost =cost*0.8;
return cost;
}
}
环境类通过类型去判断调哪种策略方法计算保费
public class Content {
private Strategy strategy;
public Content(String type) {
if (type==“children”){
this.strategy=new ChildrenStrategy();
}
if (type==“parent”){
this.strategy = new ParentStrategy();
}
}
//环境类方法计算方法
public Double contextMethod(Double cost){
return strategy.premiumFormula(cost);
}
}
测试方法
public class StrategyTest {
public static void main(String[] args) {
System./out/.println(“子女保费计算金额:”+new Content(“children”).contextMethod(100.0));
System./out/.println(“父母保费计算金额:”+new Content(“parent”).contextMethod(100.0));
}
}
责任链设计模式
主要是某个请求需要对个步骤进去处理,相当于一个链路的处理,沿着我们定义好的流程进行,相当于流程的审批。 下面举个贷款流程审批的例子,贷款人Lxlxxx审批贷款,金额<=1000的需要部门组长审批,金额>1000部门组长没有权限了,需要经理去审批,经理可以审批金额在<=2000的范围,如果金额大于2000则就需要老板审批
贷款类,包括贷款人和贷款的具体金额
public class LoansRequest {
//贷款人
private String name;
//贷款金额
private BigDecimal money;
public LoansRequest(String name, BigDecimal money) {
this.name = name;
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getMoney() {
return money;
}
public void setMoney(BigDecimal money) {
this.money = money;
}
}
定义抽象审批流程,包含审批者和下一个审批者
public abstract class SpHandler {
protected String name; // 审批者
protected SpHandler nextSpHandler; // 下一个审批者
public SpHandler(String name) {
this.name = name;
}
//审批提交
public abstract boolean spSubmit(LoansRequest loansRequest);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SpHandler getNextSpHandler() {
return nextSpHandler;
}
public void setNextSpHandler(SpHandler nextSpHandler) {
this.nextSpHandler = nextSpHandler;
}
}
三个角色分别为部门组长、经理、老板
public class FirstTrial extends SpHandler {
public FirstTrial(String name) {
super(name);
}
@Override
public boolean spSubmit(LoansRequest loansRequest) {
int result = loansRequest.getMoney().compareTo(new BigDecimal(1000));
if (result == -1) {
System./out/.println(“借款人” + loansRequest.getName() + “——“ + “贷款金额小于1000,可以允许贷款”);
return true;
} else if (result == 0) {
System./out/.println(“借款人” + loansRequest.getName() + “——“ + “贷款金额等于1000,可以允许贷款”);
return true;
}
System./out/.println(“借款人” + loansRequest.getName() + “——“ + “贷款金额大于1000,需要经理审批”);
return nextSpHandler.spSubmit(loansRequest);
}
}
public class Manager extends SpHandler {
public Manager(String name) {
super(name);
}
@Override
public boolean spSubmit(LoansRequest loansRequest) {
int result = loansRequest.getMoney().compareTo(new BigDecimal(2000));
if (result == -1) {
System./out/.println(“经理审批ing”);
System./out/.println(“借款人”+loansRequest.getName()+”——“+”贷款金额小于2000,可以允许贷款”);
return true;
} else if (result == 0) {
System./out/.println(“经理审批ing”);
System./out/.println(“借款人”+loansRequest.getName()+”——“+”贷款金额等于2000,可以允许贷款”);
return true;
}
System./out/.println(“借款人”+loansRequest.getName()+”——“+”贷款金额大于2000,需要老板审批”);
return nextSpHandler.spSubmit(loansRequest);
}
}
public class Boos extends SpHandler{
public Boos(String name) {
super(name);
}
@Override
public boolean spSubmit(LoansRequest loansRequest) {
int result = loansRequest.getMoney().compareTo(new BigDecimal(10000));
if (result == -1) {
System./out/.println(“老板审批ing”);
System./out/.println(“借款人”+loansRequest.getName()+”——“+”贷款金额小于10000,可以允许贷款”);
return true;
}
return false;
}
}
测试类
public class ResponsibilityTest {
public static void main(String[] args) {
SpHandler firstTrial = new FirstTrial(“部门组长”);
SpHandler manager = new Manager(“经理”);
SpHandler boss = new Boos(“老板”);
firstTrial.setNextSpHandler(manager);
manager.setNextSpHandler(boss);
boolean result = firstTrial.spSubmit(new LoansRequest(“Lxlxxx”, new BigDecimal(1000)));
System./out/.println(“审批结果:” + result + “\n”);
boolean result1 = firstTrial.spSubmit(new LoansRequest(“Lxlxxx”, new BigDecimal(2000)));
System./out/.println(“审批结果:” + result1 + “\n”);
boolean result2 = firstTrial.spSubmit(new LoansRequest(“Lxlxxx”, new BigDecimal(8000)));
System./out/.println(“审批结果:” + result2 + “\n”);
}
}
可以看到审批流程随着贷款金额的变化,逐渐形成了一个审批链路,达到了我们责任链的一个设计模式
总结
通过总结以上比较常用的设计模式,在日常开发中的某些场景,确实使我们的代码结构变得很清晰,也能让整个业务结构变得很清楚,由此可见设计模式的重要性,还有其他的设计模式,请评论区的小伙伴们补充。