最好的设计就是“藕断丝连”,成长为架构师的路上,需要独立思考

目录

1、代码设计必须讲究解耦合

2、解耦到处有,只遇有心人

3、最好的设计:藕断丝连

3.1 写xml文件

3.2 写一个注册中心,加载并解析Bean

3. 3、写一个接口,所有策略的“爸爸”

3.4、写一个“儿子”,实现“爸爸”的愿望

3.5、写一个实体类、一个service和一个controller,来验证我们的创新“策略模式”

4、启动项目

5、用postman测试一下


1、代码设计必须讲究解耦合

为什么要解耦合,因为耦合深的代码不仅难以维护,不好扩展,还无法复用。Java设计之初就提供了抽象类和接口来作为粘合剂,做解耦的工具。

解耦合并不是切断联系,100%的解耦就是制造信息孤岛,没有信息的交换,组件就会相互孤立,系统也就不能称为系统。

人们常说:藕断丝连,这是来形容两个人之间的感情的。我觉得来概括好的设计更为贴切,断开的两段藕相对独立,每一段藕都是一个组件,而中间的丝就是他们之间的联系,藕与丝一起组成一个完整的系统。

2、解耦到处有,只遇有心人

蜂巢快递柜将快递员和收快递的人解耦了;服务员将厨师和食客解耦了;医院的叫号系统把病患和医生解耦了;这是生活中的例子。

系统设计中一样有非常多的解耦的例子。

生产者和消费者通过消息中间件来实现解耦;

java的线程池技术将任务与执行单元解耦;

Spring容器技术将JOPO的组装和定义解耦;

Tomcat将HTTP等协议和具体的web业务解耦;

设计模式中,抽象工厂、策略模式等都是解耦思想的优秀应用。

3、最好的设计:藕断丝连

最近就有一个难题困扰着组内的同事。

我们写了一个页面,可以代理用户发布的接口。其实后台就是做一些安全处理、报文重组等业务后使用HttpClient呼叫用户真实的接口。这个主要的业务流程是没有什么问题的,关键在于不同单位对外发布的接口会有自己的安全策略,需要代理方按照发布方的安全协议去实现。一个不好的设计就是在主流程代码中把不同部门的安全协议引入,代码里会有一堆的if 、else。而且随着发布接口的部门数量的增加,我们就需要不断修改我们的业务代码(主流程中增加else),这简直槽糕透了,我不能容忍这样的做法。

认真分析完毕这个需求后,我就这件事情拆分成主流程需求和个性化需求。将个性化需求塞进“策略”,我最初想设计一个xml注册表,使用java的工具类读取并解析这个注册表,然后将自定义的“组件”放置在HashMap中(自己的容器吧),主流程代码根据一个入参去查询这个HashMap,然后根据获取的信息找到对应的策略持有者,最后调用策略持有者的方法,就可以解析个性化的“安全协议”。这其实就是“策略模式”,也许有点变种,我将new然后add变成了读取xml然后解析并放到hashMap中。

后来翻阅spring源码的时候,发现读取并且解析xml,然后把解析得到的组件放置到一个容器中正是spring最根本、最成熟的技术,那么,我何必自己实现一遍呢?用现成的它不香吗?于是有了下边这个dome。

3.1 写xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/cache
            http://www.springframework.org/schema/cache/spring-cache.xsd">

    <context:property-placeholder location="classpath*:properties/redis-config.properties" />

    <bean id="policStrategy" name="police" class="com.miller.studyredis.strategy.PolicStrategy"/>
</beans>

3.2 写一个注册中心,加载并解析Bean

package com.miller.studyredis.registercenter;

import com.miller.studyredis.strategy.CommonStrategyImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

/**
 * @program: oxnewbc
 * @description: 策略注册中心
 * @author: Miller.FAN
 * @create: 2021-07-28 15:12
 **/
@Component("registerCenter")
public class RegisterCenter {
    //spring启动时,将注册表中的策略bean解析完毕后,加载到spring容器
        private static ApplicationContext ac = new ClassPathXmlApplicationContext("spring/registration.xml");

    //根据用户参数查找解析策略所在的bean
    public CommonStrategyImpl getStrategyBean(String name) {
        return (CommonStrategyImpl) ac.getBean(name);
    }

}

3. 3、写一个接口,所有策略的“爸爸”

package com.miller.studyredis.strategy;

public interface CommonStrategyImpl {
    //用户根据策略名称可以找到相应的策略
     String strategy(String strategyName,String text) throws Exception;
}

3.4、写一个“儿子”,实现“爸爸”的愿望

package com.miller.studyredis.strategy;

import jodd.util.StringUtil;



/**
 * @program: oxnewbc
 * @description: 公安局的请求报文安全策略
 * @author: Miller.FAN
 * @create: 2021-07-27 17:47
 **/
public class PolicStrategy implements CommonStrategyImpl{

    private final static String strategyName = "police";

    //获取注册中心,从注册中心获取HashMap中的信息,拿到bean的id,就可以使用之

    @Override
    public String strategy(String strategyName,String text) throws Exception {
        System.out.println("策略名称" + strategyName);
        System.out.println("请求处理的报文" + text);
        if(StringUtil.isBlank(strategyName)) {
            throw new Exception("strategyName can't be null or '' ");
        }
        if(StringUtil.isBlank(text)) {
            throw new Exception("text can't be null or '' ");
        }
        if(strategyName.equals(strategyName)) {
            //Map<String,Object> paras = JSON.par(text,HashMap.class);
            //do nothing
        }
        return text;
    }
}

 3.5、写一个实体类、一个service和一个controller,来验证我们的创新“策略模式”

package com.miller.studyredis.entity;

/**
 * @program: oxnewbc
 * @description: 请求报文的实体类
 * @author: Miller.FAN
 * @create: 2021-07-28 16:38
 **/
public class TextBody {
    //根据该项选择使用的策略
    private String name;
    private String text;

    public TextBody() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    @Override
    public String toString() {
        return "TextBody{" +
                "name='" + name + '\'' +
                ", text='" + text + '\'' +
                '}';
    }
}
package com.miller.studyredis.service;

import com.miller.studyredis.registercenter.RegisterCenter;
import com.miller.studyredis.strategy.CommonStrategyImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @program: oxnewbc
 * @description: 策略验证接口
 * @author: Miller.FAN
 * @create: 2021-07-28 16:22
 **/
@Service
public class StrategyService {
    @Autowired
    private RegisterCenter regCenter;

    public String requestHandler(String name,String body) {
        CommonStrategyImpl strategy = regCenter.getStrategyBean(name);
        String ret = "";
        try {
            ret =  strategy.strategy(name,body);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }
}
package com.miller.studyredis.registercenter;

import com.miller.studyredis.strategy.CommonStrategyImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

/**
 * @program: oxnewbc
 * @description: 策略注册中心
 * @author: Miller.FAN
 * @create: 2021-07-28 15:12
 **/
@Component("registerCenter")
public class RegisterCenter {
    //spring启动时,将注册表中的策略bean解析完毕后,加载到spring容器
        private static ApplicationContext ac = new ClassPathXmlApplicationContext("spring/registration.xml");

    //根据用户参数查找解析策略所在的bean
    public CommonStrategyImpl getStrategyBean(String name) {
        return (CommonStrategyImpl) ac.getBean(name);
    }

}

4、启动项目

我写的是一个spring boot工程

 5、用postman测试一下

6、看一下日志

日志中的文字正是我们希望打印的内容,而Postman测试返回的报文也正是我们police对应的策略返回的。dome达到了我们设计的目标。 

在成为架构师的道路上不断探索,有所创新。我就是Miller.Fan,一个设计狂人。

客观,站住,点个赞再走,我们拒绝白piao的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值