一、外观模式介绍
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
四、外观模式构造
- 外观(Facade)提供了一种拜访特定子系统性能的便捷形式,其理解如何重定向客户端申请,通晓如何操作所有流动不见。
- 创立附加外观(Additional Facade)类能够防止多种不相干的性能净化繁多外观,使其变成又一个简单构造。客户端和其余外观都可应用附加外观。
- 简单子系统(Complex Subsystem)有数十个不同对象形成。如果要用这些对象实现有意义的工作,必须理解子系统的实现细节,比方依照正确程序初始化对象和为其提供正确格局的数据。
子系统类不会意识到外观的存在,它们在零碎内运作并且相互之间可间接进行交互。
- 客户端(Client)应用外观代替对子系统对象的间接调用。
设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深刻设计模式:https://refactoringguru.cn/design-patterns/catalog