【mybatis】Mybatis中的设计模式——Builder 模式

【mybatis】简介

【mybatis】mybatis & mybatis-plus & hibernate的区别

【mybatis】核心成员分析

【mybatis】Mybatis的工作流程

【mybatis】Mybatis中的一级、二级缓存

目录

概览

Builder 模式

实现

官方Demo

Mybatis里的Builder模式


概览

Mybatis是一款优秀的框架,里面也使用了以下几种设计模式供我们参考

  • Builder 模式:例如 SqlSessionFactoryBuilderXMLConfigBuilderXMLMapperBuilderXMLStatementBuilderCacheBuilder
  • 工厂模式:例如SqlSessionFactoryObjectFactoryMapperProxyFactory
  • 单例模式:例如ErrorContextLogFactory
  • 代理模式:Mybatis实现的核心,比如MapperProxyConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
  • 组合模式:例如SqlNode和各个子类ChooseSqlNode等;
  • 模板方法模式:例如BaseExecutorSimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler
  • 适配器模式:例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
  • 装饰者模式:例如cache包中的cache.decorators子包中等各个装饰者的实现;
  • 迭代器模式:例如迭代器模式PropertyTokenizer

Builder 模式

Builder 模式也叫建造者模式,它是使用多个简单的对象一步一步构建成一个复杂的对象,它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

实现

官方Demo

我们拿麦当劳为例:

一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)。

汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。

冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。

我们将创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中。

然后我们创建一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilderBuilderPatternDemo,我们的演示类使用 MealBuilder 来创建一个 Meal

建造者模式的 UML 图

Item:用户点的食物清单List里的,定义每一种食物的属性接口,比如:

食物名称(鸡肉汉堡)、食物包装(纸盒装的)、食物价格(50块钱)

食物名称(可口可乐)、食物包装(瓶装的)、食物价格(30块钱)

。。。。。。。。

package com.maple.mybatis.design.patterns.builder;

/**
 * 食物条目(汉堡和冷饮)
 */
public interface Item {

    /**
     * 名称:鸡肉汉堡
     *
     * @return
     */
    String name();

    /**
     * 食物包装:汉堡是包在纸盒中,冷饮是装在瓶子中。
     *
     * @return
     */
    Packing packing();

    /**
     * 价格
     *
     * @return
     */
    float price();
}

Packing:食物的包装接口

package com.maple.mybatis.design.patterns.builder;

/**
 * 包装:纸盒 和 瓶子 都会实现改接口
 */
public interface Packing {

    String pack();
}

食物的包装接口实现类,有两种包装,纸盒 + 瓶装

Wrapper:纸盒包装

package com.maple.mybatis.design.patterns.builder;

/**
 * 纸盒包装
 */
public class Wrapper implements Packing {

    public String pack() {
        return "Wrapper";
    }
}

 Bottle:瓶装

package com.maple.mybatis.design.patterns.builder;

/**
 * 瓶子包装
 */
public class Bottle implements Packing {

    public String pack() {
        return "Bottle";
    }
}

食物类目接口的实现类,因为我们有 汉堡和饮品 两种食物

Burger:汉堡

因为目前只知道汉堡是用纸盒包装的,不知道是鸡肉还是蔬菜汉堡,以及他们的价格,所以我们把Burger定义为基类,具体的食物名称和价格我们留给子类去重写

package com.maple.mybatis.design.patterns.builder;

/**
 * 汉堡实现Item接口
 */
public abstract class Burger implements Item {

    public Packing packing() {
        return new Wrapper();
    }

    public abstract float price();
}

 ChickenBurger:鸡肉汉堡

package com.maple.mybatis.design.patterns.builder;

/**
 * 鸡肉汉堡,继承Burger,是纸盒的
 */
public class ChickenBurger extends Burger {

    public String name() {
        return "Chicken Burger";
    }

    public float price() {
        return 50.5f;
    }
}

VegBurger:蔬菜汉堡

package com.maple.mybatis.design.patterns.builder;

/**
 * 蔬菜汉堡,继承Burger,是纸盒的
 */
public class VegBurger extends Burger {

    public String name() {
        return "Veg Burger";
    }

    public float price() {
        return 25.0f;
    }
}

ColdDrink:冷饮

因为目前只知道冷饮是瓶装的,不知道是可口可乐还是东鹏特饮,以及他们的价格,所以我们把ColdDrink定义为基类,具体的食物名称和价格我们留给子类去重写

package com.maple.mybatis.design.patterns.builder;

/**
 * 冷饮实现Item接口
 */
public abstract class ColdDrink implements Item {

    public Packing packing() {
        return new Bottle();
    }

    public abstract float price();
}

Coke:可口可乐

package com.maple.mybatis.design.patterns.builder;

/**
 * 都是冷饮,继承ColdDrink,瓶装的
 */
public class Coke extends ColdDrink{

    public String name() {
        return "Coke";
    }

    public float price() {
        return 30.0f;
    }
}

Pepsi:东鹏特饮

package com.maple.mybatis.design.patterns.builder;

/**
 * 都是冷饮,继承ColdDrink,瓶装的
 */
public class Pepsi extends ColdDrink{

    public String name() {
        return "Pepsi";
    }

    public float price() {
        return 35.0f;
    }
}

Meal:吃晚餐了,我们可以给我们的晚餐里增加食物;看看我们这顿饭都点了啥;一共花了多少钱

package com.maple.mybatis.design.patterns.builder;

import java.util.ArrayList;
import java.util.List;

/**
 * 吃晚餐了:我们可以给我们的晚餐里增加食物;看看我们这顿饭都点了啥;一共花了多少钱
 */
public class Meal {

    private List<Item> items = new ArrayList<Item>();

    public void addItem(Item item) {
        items.add(item);
    }

    public float getCost() {
        float cost = 0.0f;
        for (Item item : items) {
            cost += item.price();
        }
        return cost;
    }

    public void showItems() {
        for (Item item : items) {
            System.out.print("Item : " + item.name());
            System.out.print(", Packing : " + item.packing().pack());
            System.out.println(", Price : " + item.price());
        }
    }
}

MealBuilder:我们开始对外推出我们的套餐组合

有蔬菜汉堡+可乐组合,还有鸡肉汉堡+东鹏特饮组合。。。商家可以随意进行搭配

package com.maple.mybatis.design.patterns.builder;

/**
 * 麦当劳套餐组合
 */
public class MealBuilder {

    /**
     * 蔬菜汉堡和Coke饮品
     *
     * @return
     */
    public Meal prepareVegMeal() {
        Meal meal = new Meal();
        meal.addItem(new VegBurger());
        meal.addItem(new Coke());
        return meal;
    }

    /**
     * 鸡肉汉堡和Pepsi饮品
     *
     * @return
     */
    public Meal prepareNonVegMeal() {
        Meal meal = new Meal();
        meal.addItem(new ChickenBurger());
        meal.addItem(new Pepsi());
        return meal;
    }
}

BuilderPatternDemo:那么当用户购买参套组合的时候,就可以看到每个组合里都有什么食物,如果套餐里没有的话,还可以继续增加食物,也可以实时看到价格

package com.maple.mybatis.design.patterns.builder;

/**
 * 用户开始点餐了
 * 展示用户点餐的类目和价格
 */
public class BuilderPatternDemo {

    public static void main(String[] args) {
        MealBuilder mealBuilder = new MealBuilder();

        // A用户来份蔬菜汉堡+可口可乐套餐
        Meal vegMeal = mealBuilder.prepareVegMeal();
        System.out.println("Veg Meal");
        vegMeal.showItems();
        System.out.println("Total Cost: " +vegMeal.getCost());

        // B用户来份鸡肉汉堡+东鹏特饮套餐
        Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
        System.out.println("\n\nNon-Veg Meal");
        nonVegMeal.showItems();
        System.out.println("Total Cost: " +nonVegMeal.getCost());

        // B用户在上面的套餐基础上又增加了 一个蔬菜汉堡
        nonVegMeal.addItem(new VegBurger());
        System.out.println("\n\nNon-Veg Meal 增加蔬菜汉堡之后....");
        nonVegMeal.showItems();
        System.out.println("Total Cost: " +nonVegMeal.getCost());
    }
}

Mybatis里的Builder模式

例如:SqlSessionFactoryBuilderXMLConfigBuilderXMLMapperBuilderXMLStatementBuilderCacheBuilder

SqlSessionFactoryBuilderXMLConfigBuilderXMLMapperBuilderXMLStatementBuilder 这几个都是有多个参数,不同的参数去设置不同的属性,所以使用了Builder模式,但是这里也说不上好与坏,因为这里不用Builder模式,只使用构造器方式来创建对象也完全OK的。

CacheBuilder这里就是规范的Builder模式啦,我们一起来看一下。

首先就是每个字段给一个构建方法

 每个字段构建完成之后,利用这些字段开始创建所需要的对象

调用方随意组合自己所需要的字段,最后调用build()方法开始创建对象

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

maple 枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值