一、外观模式介绍

1. 解决的问题

次要解决拜访简单零碎的外部子系统的复杂度问题,简化客户端与其子系统的接口。

2. 定义

外观模式是一种结构型设计模式,能为程序库、框架或其余简单类提供一个简略的接口。

3. 利用场景

  • 须要一个指向简单子系统的间接接口,且该接口的性能无限,能够应用外观模式。
  • 须要将子系统组织为多层构造,能够应用外观模式。

二、外观模式优缺点

1. 长处

  • 能够让代码独立于简单子系统。

2. 毛病

  • 外观可能成为与程序中所有类都耦合的上帝对象。

三、外观模式利用实例:类型转换器

1. 实例场景

在咱们的工作中,经常会遇到一些类型转换的问题,比方将一个数组转换成字符串等,咱们通常会用一些第三方工具类库来实现,比方 Hutool ,这种工具类库其实就是蕴含外观模式的思维,咱们无需关注外部如何实现类型转换,只需依据办法阐明传参即可获取咱们想要的转换后果。

明天就以类型转换为例,介绍一下如何应用外观模式。

2. 外观模式实现

2.1 工程构造
facade-pattern└─ src    ├─ main    │    └─ java    │    └─ org.design.pattern.facade    │       ├─ convert    │       │    └─ Convert.java    │       ├─ converter    │       │    └─ StringConverter.java    │       ├─ text    │       │    └─ ASCIIStrCache.java    │       └─ utils    │            ├─ ArrayUtil.java    │            └─ CharUtil.java    └─ test        └─ java            └─ org.design.pattern.facade.test                  └─ ConvertTest.java
2.2 代码实现
2.2.1 Facade
/** * 类型转换 */public class Convert {    /**     * 转换为字符串     * 如果给定的值为null,或者转换失败,返回null     * 转换失败不会报错     *     * @param value 被转换的值     * @return String     */    public static String toString(Object value) {        return StringConverter.convertToStr(value);    }}
2.2.2 转换器

字符串转换器

/** * 字符串转换器 */public class StringConverter {    /**     * 数据转为String     * 转换规则为:     * 1、字符串类型将被强转     * 2、数组将被转换为逗号分隔的字符串     * 3、其它类型将调用默认的toString()办法     *     * @param value 数据     * @return String     */    public static String convertToStr(Object value) {        if (null == value) {            return null;        }        if (value instanceof CharSequence) {            return value.toString();        } else if (ArrayUtil.isArray(value)) {            return ArrayUtil.toString(value);        } else if(CharUtil.isChar(value)) {            //对于ASCII字符应用缓存减速转换,缩小空间创立            return CharUtil.toString((char)value);        }        return value.toString();    }}
2.2.3 文本操作

ASCII字符串缓存

/** * ASCII字符串缓存 */public class ASCIIStrCache {    private static final int ASCII_LENGTH = 128;    private static final String[] CACHE = new String[ASCII_LENGTH];    static {        for (char c = 0; c < ASCII_LENGTH; c++) {            CACHE[c] = String.valueOf(c);        }    }    /**     * 字符转为字符串     * 如果为ASCII字符,应用缓存     *     * @param c 字符     * @return 字符串     */    public static String toString(char c) {        return c < ASCII_LENGTH ? CACHE[c] : String.valueOf(c);    }}
2.2.4 工具类

数组工具类

/** * 数组工具类 */public class ArrayUtil {    /**     * 对象是否为数组对象     *     * @param obj 对象     * @return 是否为数组对象,如果为空 返回false     */    public static boolean isArray(Object obj) {        if (null == obj) {            return false;        }        return obj.getClass().isArray();    }    /**     * 数组或汇合转String     *     * @param obj 汇合或数组对象     * @return 数组字符串,与汇合转字符串格局雷同     */    public static String toString(Object obj) {        if (null == obj) {            return null;        }        if (obj instanceof long[]) {            return Arrays.toString((long[]) obj);        } else if (obj instanceof int[]) {            return Arrays.toString((int[]) obj);        } else if (obj instanceof short[]) {            return Arrays.toString((short[]) obj);        } else if (obj instanceof char[]) {            return Arrays.toString((char[]) obj);        } else if (obj instanceof byte[]) {            return Arrays.toString((byte[]) obj);        } else if (obj instanceof boolean[]) {            return Arrays.toString((boolean[]) obj);        } else if (obj instanceof float[]) {            return Arrays.toString((float[]) obj);        } else if (obj instanceof double[]) {            return Arrays.toString((double[]) obj);        } else if (ArrayUtil.isArray(obj)) {            // 对象数组            try {                return Arrays.deepToString((Object[]) obj);            } catch (Exception e) {                // 不操作            }        }        return obj.toString();    }}

字符工具类

/** * 字符工具类 */public class CharUtil {    /**     * 给定对象对应的类是否为字符类,字符类包含:     * Character.class     * char.class     *     * @param value 被查看的对象     * @return true示意为字符类     */    public static boolean isChar(Object value) {        // noinspection ConstantConditions        return value instanceof Character || value.getClass() == char.class;    }    /**     * 字符转为字符串     * 如果为ASCII字符,应用缓存     *     * @param c 字符     * @return 字符串     */    public static String toString(char c) {        return ASCIIStrCache.toString(c);    }}
2.3 测试验证
2.3.1 测试验证类
/** * 转换测试类 */public class ConvertTest {    private final Logger log = LoggerFactory.getLogger(ConvertTest.class);    @Test    public void testConvertString() {        int number = 1;        log.info("int number = 1 convert string : " + Convert.toString(number));        char charString = 'a';        log.info("char charString = 'a' convert string : " + Convert.toString(charString));        long[] array = {1,2,3,4,5};        log.info("long[] array = {1,2,3,4,5} convert string : " + Convert.toString(array));    }}
2.3.2 测试后果
14:50:51.514 [main] INFO  o.d.pattern.facade.test.ConvertTest - int number = 1 convert string :114:50:51.517 [main] INFO  o.d.pattern.facade.test.ConvertTest - char charString = 'a' convert string :a14:50:51.517 [main] INFO  o.d.pattern.facade.test.ConvertTest - long[] array = {1,2,3,4,5} convert string :[1, 2, 3, 4, 5]Process finished with exit code 0

四、外观模式构造

  1. 外观(Facade)提供了一种拜访特定子系统性能的便捷形式,其理解如何重定向客户端申请,通晓如何操作所有流动不见。
  2. 创立附加外观(Additional Facade)类能够防止多种不相干的性能净化繁多外观,使其变成又一个简单构造。客户端和其余外观都可应用附加外观。
  3. 简单子系统(Complex Subsystem)有数十个不同对象形成。如果要用这些对象实现有意义的工作,必须理解子系统的实现细节,比方依照正确程序初始化对象和为其提供正确格局的数据。

    子系统类不会意识到外观的存在,它们在零碎内运作并且相互之间可间接进行交互。

  4. 客户端(Client)应用外观代替对子系统对象的间接调用。

设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。

源码地址:https://github.com/yiyufxst/design-pattern-java

参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深刻设计模式:https://refactoringguru.cn/design-patterns/catalog