首页 > 编程语言 >将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)

将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)

时间:2024-01-20 15:32:52浏览次数:32  
标签:return 适配器 List 工厂 源码 监听器 new public


前言

咋说呢,大学期间阅读过很多源码(Aop、Mybatis、Ioc、Spring Mvc…),刚开始看这些源码的时候觉得云里雾里,一个没什么代码量的人突然去接触这种商业帝国级别的成品源码的时候,根本无从下手,这种感觉很难受,但是也庆幸自己熬过了那段难忘且充实的日子,随着自己代码量的慢慢增多,也开始慢慢的融入了自己的一点小思想带入到开发中来。

设计模式精髓个人理解

适配器模式顾名思义适配器的存在就是为了去适配别人的,别人发现 X 适配器适配自己,于是就叫 X 适配器来帮干活。这个时候有人站出来说了,老哥我懂是懂你说的这些大白话,但是如果用代码怎么来实现呢?通过分析理论,我们可以得知适配器的几大核心要素:

  1. 适配器如何去适配别人? 答:适配器需要提供一个适配别人的方法 <IsSupport()>
  2. 如何实现这个适配别人的方法呢? 答:可以通过别人(类属性)中的某个属性适配,或者直接通过别人的类别适配< Instanceof >
  3. 匹配上了对应的适配器,适配器是如何帮客户干活的呢?答:适配器需要提供一个干活的方法。例如< Production() >

工厂模式: 顾名思义就是一种工厂的运转模式,而且一个正规的工厂一定有这俩个基础的职责存在。

  1. 工厂里面有很多部门 。(工厂属性)
  2. 每当有任务过来的时候,工厂可以很快将任务分配到指定部门的手中,让其部门执行生产命令。(工厂行为)

小结:工厂可以直接生产商品(小作坊般的存在,量级太小,用不用工厂模式运转都无所谓)、工厂负责管理部门让其生产商品(正规军,流程职责分明)

直接上正菜(工厂规范接口定义)

就拿玩具工厂举例子。采用函数式约定一下工厂的规范。注意:I,O是泛型,更具泛用性。并且结合了一下适配器模式,方法的返回值是 Adapter。

@FunctionalInterface
public interface Factory<I, O> {
    Adapter<I, O> findAdapter(I var1);
}

适配器接口定义

根据上文中的理论定义这么一个适配器接口

public interface Adapter<I, O> {
    /**
     * 适配器适配哪些数据类型
     */
    Boolean isSupport(I input);

    /**
     * 适配器的类型
     */
    List<String> types();

    /**
     * 适配器真正干活的方法
     */
    List<O> production(Map<String, Object> map);
}

抽象工厂定义

定义抽象的工厂,里面实现了一个 FindAdapter 的方法(遍历所有可用的适配器,找到支持处理 I input 数据类型的适配器,没找到返回 null ),将 AvailableAdapters()定义为抽象方法,具体的实现交给子类。

public abstract class AbstractFactory<I, O> implements Factory<I, O> {
    public Adapter<I, O> findAdapter(I input) {
        return this.availableAdapters().stream().filter((d) -> {
            return d.isSupport(input);
        }).findFirst().orElse(null);
    }

    public abstract List<? extends Adapter<I, O>> availableAdapters();
}

Spring加强工厂定义

结合 Spring 中的监听器,通过Spring上下文对象,获取所有适配器类型的 Bean 放到工厂定义的 adapterList属性中。然后重写抽象工厂中的 AvailableAdapters 方法 return 所有注册过的适配器,这样一来无论是什么种类的适配器,都可以在我们编写的工厂中被寻找到。这种写法很妙吧哈哈哈哈。可能很多人会问:如果此时的适配器还没有注册到IOC 容器中咋办呢????

public class SpringAwareFactory<D extends Adapter<I, O>, I, O> extends AbstractFactory<I, O> implements ApplicationListener<ContextRefreshedEvent> {
    private final List<D> adapterList = new LinkedList<>();

    @Override
    public List<? extends Adapter<I, O>> availableAdapters() {
        return this.adapterList;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        contextRefreshedEvent.getApplicationContext().getBeansOfType(Adapter.class).values().stream().forEach(d -> {
            adapterList.add((D) d);
        });
        System.err.println(adapterList);
    }
}

下图一圈红的地方是具体的监听器的执行入口,我们可以看到他的上一步之行了 this.finishBeanFactoryInitialization(beanFactory) 这个方法,里面会进行注册初始化项目扫描到的所有 Bean(具体的Spring源码不做过多解释)。读者只需知道在监听器里,获取到的所有的 Bean 都是完整的。

将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)_适配器模式

玩具工厂的定义

继承 Spring加强工厂即可满足使用,无需扩展其他方法

@Component
public class SpringToyFactory extends SpringAwareFactory {
    @Override
    public List<? extends Adapter> availableAdapters() {
        return super.availableAdapters();
    }
}

到此工厂代码堡垒的搭建雏形已经出来了~~~~~~~~~

抽象适配器开发

老道理定义一个万能抽象类,将泛型具象化,实现了 Production 方法,但是具体的生产原料的方法给抽象出去了,具体的实现交给子类了。这样更灵活一点,将代码进行了一个结耦操作。拿个例子举例来说,不论是什么种类的冰棍的生产过程是不是都是一样的,只是说有原料上的不同而已,如果从代码角度上进行优化我们是不是可以将冰棍的生产过程进行一个拆分出来,达到一个解耦的目的。下面的抽象类运用的也是这么一个思想,然后抽象类中的 IsSupport 方法里面利用到了 Types 方法,Types 方法的实现也是交给子类实现的,只是说为其子类封装好了特定的逻辑而已。仔细想想这种思想在生活中是不是也很常见呢?一切本着简化操作的理念,用户只需付出很少的学习成本,就可以实现复杂需求的目标。是不是很人性化化呢哈哈哈

/**
 * 具体的生产玩具的逻辑在这,抽象类抽象出去的方法只是一个提供原料的方法
 */
public abstract class AbstractAdapter implements Adapter<InputData, ToyDog>, StockHandler {
    @Override
    public Boolean isSupport(InputData input) {
        return this.types().contains(input.getType());
    }

    @Override
    public List<ToyDog> production(Map<String, Object> map) {
        ArrayList<ToyDog> toys = new ArrayList<>();
        List<Object> abstractAstocks = this.getStocks(map);
        ArrayList<Map<String, Object>> realStocks = new ArrayList<>();
        abstractAstocks.stream().forEach(a -> {
            Map<String, Object> stock = this.HandlerStock(a);
            realStocks.add(stock);
        });
        realStocks.stream().forEach(realStock -> {
            ToyDog toyDog = new ToyDog();
            toyDog.setId((String) realStock.get("id"));
            toyDog.setName((String) realStock.get("name"));
            toyDog.setColor((String) realStock.get("color"));
            toys.add(toyDog);
        });
        return toys;
    }

    public abstract List<Object> getStocks(Map<String, Object> map);
}

抽象适配器子类

代码逻辑很简单,给自己贴标签,说自己是猫玩具生产部门、只提供生产猫玩具的原料

@Component
public class CatDepartmentAdapter extends AbstractAdapter {
    @Override
    public List<Object> getStocks(Map<String, Object> params) {
        ArrayList<Toy> toys = new ArrayList<>();
        ToyCat catone = new ToyCat("猫一", "黄");
        ToyCat cattwo = new ToyCat("猫二", "红");
        catone.setId("1");
        cattwo.setId("2");
        toys.add(catone);
        toys.add(cattwo);
        ArrayList<Object> res = new ArrayList<>();
        toys.stream().forEach(a -> {
            res.add(a);
        });
        return res;
    }

    @Override
    public List<String> types() {
        ArrayList<String> res = new ArrayList<>();
        res.add("cat");
        return res;
    }
}

提供一个类似于 DispatcherServlet 的 Service

依旧是本着解耦以及流程化开发的原则,一个餐馆开张的几个前提是,具备从业资格证或者最起码提供的午餐也是获得 3C 认证的吧(一本正经的胡说八道),本着这种设计理念,我们也为我们的玩具工厂制定一些规则。于是乎我们开放了这么一个入口,用于生产玩具前的规则校验。就是遍历所有已注册的适配器,无则抛出对应提示,有则执行对应适配器中的方法。

@Service
public class ToyService {
    @Autowired
    private SpringToyFactory toyFactory;

    public List<ToyDog> production(InputData inputData) {
        return this.doProduction(inputData, toyFactory);
    }

    public List<ToyDog> doProduction(InputData inputData, SpringToyFactory springToyFactory) {
        Iterator<? extends Adapter> adapters = springToyFactory.availableAdapters().iterator();
        do {
            Adapter adapter = adapters.next();
            Assert.notNull(adapter, "没有注册%s类型的Department", inputData.getType());
            if (adapter.isSupport(inputData)) {
                return adapter.production(inputData.getParams());
            }
        } while (adapters.hasNext());
        throw new RuntimeException("不支持的" + inputData.getType() + "类型");
    }
}

下面的代码是我从 Spring Mvc 源码中摘出来的一小段源码,也是我参考的源代码哈哈哈哈哈,具体的 Spring Mvc 源码分析在我以前的文章中有的。

将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)_java基础_02

单元测试

用我们的玩具工厂生产几个只玩具狗试试,可以看到都和预期的结果一样

@Test
    void toys() {
        InputData inputData = new InputData();
        inputData.setType("dog");
        List<ToyDog> production = toyService.production(inputData);
        production.stream().forEach(p -> {
            System.err.println(p.toString());
        });
    }

将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)_工厂模式_03

附页

将对象转map,具体的实现细节可以参考这篇博客 Spring提供的BeanUtils源码剖析(附手写copyProperties方法)

public interface StockHandler {
    default Map<String, Object> handlerStock(Object stock) {
        HashMap<String, Object> resMap = new HashMap<>();
        try {
            PropertyDescriptor[] targetPds = Introspector.getBeanInfo(stock.getClass()).getPropertyDescriptors();
            Arrays.stream(targetPds).forEach(targetPd -> {
                try {
                    Object value = targetPd.getReadMethod().invoke(stock);
                    String key = targetPd.getName();
                    String name = Character.toLowerCase(key.charAt(0)) + key.substring(1);
                    resMap.put(name, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            });
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
        return resMap;
    }
}

玩具狗结构

将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)_java_04


将小部分源码设计精髓带入到开发中来(工厂模式、适配器模式、抽象类、监听器)_工厂模式_05

本文技术总结

1: 代码解耦我永远的神:通过接口接口,写default修饰的方法
2: 代码解耦我永远的神:通过工厂设计模式,将对象的创建与使用分离开来
3: 代码解耦我永远的神:通过适配器设计模式,将一个小业务抽离成一个小适配器,用于适配不同业务

结语

标签:return,适配器,List,工厂,源码,监听器,new,public
From: https://blog.51cto.com/u_16414043/9345742

相关文章

  • 直播app系统源码,通过延迟加载非关键资源实现首屏优化
    直播app系统源码,通过延迟加载非关键资源实现首屏优化将非关键资源(如广告、推荐内容等)的加载延迟到首屏渲染完成之后,以提高首屏展示速度。<!DOCTYPEhtml><html><head><title>延迟加载示例</title></head><body><h1>首屏内容</h1><!--非关键资源--><d......
  • 视频直播app源码,利用缓存实现连续登录失败后的时间等待
    实现步骤:1、用户在视频直播app源码中发起登录请求2、后台验证是否失败次数过多,账户没有锁定的话就进入下面的步骤;否则直接返回3、验证用户的账号+密码3.1验证成功:删除缓存3.2验证失败:统计最近10分钟时间窗口内的失败次数,如果达到5次则设置锁定缓存,返回图解实......
  • MetaGPT day02: MetaGPT Role源码分析
    MetaGPT源码分析思维导图MetaGPT版本为v0.4.0,如下是frommetagpt.rolesimportRole,Role类执行Role.run时的思维导图:概述其中最重要的部分是_react,里面包含了一个循环,在循环中交替执行_think和_act,也就是让llm先思考再行动。_think中决定了llm下一个执行的动作是什么,这个动作......
  • TCP三次握手源码分析(服务端接收ACK&TCP连接建立完成)
    内核版本:Linux3.10内核源码地址:https://elixir.bootlin.com/linux/v3.10/source(包含各个版本内核源码,且网页可全局搜索函数)《TCP三次握手源码分析(客户端发送SYN)》《TCP三次握手源码分析(服务端接收SYN以及发送SYN+ACK)》《TCP三次握手源码分析(客户端接收SYN+ACK以及发送ACK......
  • Java登陆第三十一天——监听器
    逻辑上与JS中的事件差不多。被监视的对象触发某些情况,自动执行监听器。不同于JS的事件,监听器只负责监听三大域对象的相关事件,例如:域对象的创建域对象的销毁域对象数据增删改八个监听器Tomcat提供了八个监听器接口作为监听器的规范。应用域域监听器ServletCont......
  • 《Java并发实现原理:JDK源码剖析》PDF
    《Java并发实现原理:JDK源码剖析》全面而系统地剖析了JavaConcurrent包中的每一个部分,对并发的实现原理进行了深刻的探讨。全书分为8章,第1章从最基础的多线程知识讲起,理清多线程中容易误解的知识点,探究背后的原理,包括内存重排序、happen-before、内存屏障等;第2~8章,从简单到复杂,逐......
  • 《Java并发实现原理:JDK源码剖析》PDF
    《Java并发实现原理:JDK源码剖析》全面而系统地剖析了JavaConcurrent包中的每一个部分,对并发的实现原理进行了深刻的探讨。全书分为8章,第1章从最基础的多线程知识讲起,理清多线程中容易误解的知识点,探究背后的原理,包括内存重排序、happen-before、内存屏障等;第2~8章,从简单到复杂,逐......
  • A021 《斗图大赛》编程 源码
    一、课程介绍本节课将学习新的while循环,并结合布尔值True实现无限循环,最终实现一个动态表情包的效果。二、重难点解析布尔值在编程中,True是真,False是假。“真,假”,也是“对,错”的意思,它们是由英国著名数学家和逻辑学家乔治布尔提出的。所以,True和False也叫做布尔值,用于表示......
  • 纯网页语音视频聊天和桌面分享(附源码,PC版+手机版)
    在网页里实现文字聊天是比较容易的,但若要实现视频聊天,就比较麻烦了。本文将实现一个纯网页版的视频聊天和桌面分享的Demo,可直接在浏览器中运行,不需要安装任何插件。一.主要功能及支持平台1.本Demo的主要功能有(1)一对一语音视频聊天。(2)远程桌面观看。(3)当客户端掉线时,会......
  • 若依框架入门一源码分析一登录验证码
    若依框架入门一源码分析一关于登录页面的验证码问题前端页面的验证码开关设置的是true,但是打开画面验证码没有被显示,原因是后端代码判断了redis中是否有值,有则覆盖前端<el-form-itemprop="code"v-if="captchaEnabled"><el-inputv-model="loginForm......