提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
快要考试了,这里再记录一下剩下的一点设计模式和正则表达式,还有最后一章有关异常的复习知识
面向可维护性的设计模式
工厂方法
当客户端不知道要创建哪个具体类的实例,或者不想在客户端代码中指明要具体创建的实例时,用工厂方法。
想要隐藏右下角的两个子类,ProductOne和ProductTwo,用一个接口继承树来进行隔离。常规条件下的调用应该是 Product p = new ProductTwo()
但是用了工厂方法以后是Product p = new ConcreteTwo () . makeObject()
这个模式还是典型的,接口之间存在delegation,不同的接口存在子类型
具体代码的例子:
我的ADT的接口:
ADT的两个实现:
此时按照正常结果,调用的形式是:
然后我们加入工厂方法:
工厂方法接口:
工厂方法接口的两个实现:不过更偏向第一种,第二种的if else违背OCP原则,不如每个方法都创建一个实现
这时候客户端的调用:通过new factory().getTrace()通过接口调用构造方法
不过在各个实现的子类中可以使用静态方法,直接省去new factory的操作:
这时候的客户端调用:
Visitor 模式
依然是两个继承树之间的delegation模式
在后续维护时候需要对ADT增加新的方法(不是增加功能,而是要整个ADT增加方法),但是修改ADT以修改方法是违反OCP原则的。那么使用visitor方法提前做好准备,预先准备一个accept方法,传进来一个visitor方法,以进行delegation另一个继承树。传进来一个什么样子的visitor的子类型,我就进行什么样的方法扩展。
例子:
我们ADT的接口如下,这里只展示了accept
我们ADT接口的实现:在每个实现中调用了visitor对象的visit方法,参数是自己也就是this
然后visitor抽象类中,对book和fruit扩展方法,在它的实现中,也会有book或者fruit的参数传入。因此实现的方法中也可以调用之前方法中的实现,这是属于双向的调用
客户端的实现:通过传入visitor,调用accept方法计算价值。
与strategy模式的对比:
几种模式的对比
Adaptor 一棵继承树
Template 一棵继承树
Strategy 两棵继承树(两个层次的delegation)
Iterator 两棵继承树
工厂方法
正则表达式
几种基本操作符:
一个字符串连接的例子:
扩展操作符:
x : : = y ? y出现或者不出现
x :: = 【a-c】x取a到c中间任意一个
x :: = 【aeiou】x取aeiou中间任意一个
x :: = 【^a-c】范围取反
区分正则语法和正则表达式
正则语法(没有递归)
正则语法定义: 简化之后可以表达为一个产生式而不包含任何非终止节点
例子:
正则表达式
概念: 去除引号和空格,从而表达更简洁(更难懂)
简化操作符
一个点”.“——任何字符
\d——0-9
\s——空白符
\w——大写小写字母,下划线,数字
斜杠是转义符
例子:
健壮性与正确性
健壮性
主要是对外部的接口倾向于健壮性,尽量保持程序能够继续运行下去的,容忍一些错误
包含一些容错机制,客户端更容易一些
——用户更加容易
概念:系统在不正常输入或不正常外部环境下仍能够表现正常的程度
面向健壮性的编程:
处理未期望的行为和错误终止
即使终止执行,也要准确无歧义的的向用户展示全面的错误信息
错误信息有助于进行debug
正确性
对内的实现,倾向于正确性,程序按照spec加以执行的能力,最重要的质量指标
永远不给用户错误的结果,不符合precondition直接返回错误
——程序员更加容易
可靠性
reliability = robustness + correctness
几个常用的术语
error ——>程序员的错误
defect(缺陷)/ fault / bug ——> 缺陷
failure——> 失效,运行时的外在表现
因果关系:
error——> defect/ fault/ bug ——> failure
异常
error与exception比较
error ——>错误:外部的原因而不是程序本身的问题
例如:
用户输入错误
设备错误
物理限制
典型的几个error:
exception ——> 异常:自身程序导致的问题,可以捕获,可以处理
exception
例子:
throws 与 return
正常的退出方式:return
异常退出方式: throws
exception的RuntimeException
exception分为RuntimeException和其他异常
RuntimeException:运行时异常,由程序员在代码里处理不当造成(动态检查)
其他异常:由外部原因造成,但是这是可以由程序内部进行解决的(error是无能为力的)
RuntimeException:(暴露给程序员的)
例如:错误的类型转换
数组越界
空指针异常
其他异常:(可以解决问题)
例如:
试图读最后一行的后面(程序可以自行判断)
读不存在的文件
这些问题就算程序员在程序中做出了相关处理,但是还是不能完全避免他们的发生
check异常和unchecked异常
checked 异常是非运行阶段异常——静态检查,编译器检查是否进行了try catch
——可以补救的异常,比如文件打不来,可以循环再次输入文件名
unchecked 异常是运行阶段异常和error——动态类型检查,编译器不会进行检查
——不能补救的异常,
unchecked异常
例子:
空指针异常是unchecked 异常,在程序内部应该做出一定的修改,在调用那个句子之前进行判断
数组越界异常是unchecked异常,在语句之前判断索引值
类型转换错误,unchecked异常,可以自行内部进行类型判断
也可以进行捕获,但是这样的处理是没有意义的,必须要修改代码,再方法名后面进行标注也没有意义,强烈不建议!!!
在方法名后面有标注的都是checked异常!
checked 异常
优雅的形式退出,运行阶段发生的unchecked异常则强行退出
几种处理方法
try catch
throws
在方法的spec中,告诉客户端,这里的异常没有进行处理,在客户端要注意处理
在方法名后面有标注的都是checked异常!!这里可以标注多个异常
相当于有可能返回是return是int也有可能是返回一个异常
throws的异常有两个来源,要么是当前方法检测到的错误并且抛出
要么是调用的函数抛出,从被调用的函数传递来的异常
不要在main函数再进行throws操作,应该再调用链中至少有一个地方进行了try catch
断言与防御式编程
exception 提高健壮性
断言与防御式编程 提高正确性
assert不满足的话,会抛出AssertionError
断言主要用于开发阶段,避免引入和帮助发现BUG
而运行阶段用的是exception
实际运行阶段,不再使用断言——>影响健壮性
避免降低性能
语法例子:
例子:
assert在何处调用
其中控制流不变量:
注意:
remove是需要的操作,如果禁用assert那么会影响操作
外部的文件输入等无法控制的事情,不用assert而是用exception
private 方法中可以用assert
private 方法中可以用assert,因为这不对客户端开放
return之前的assert
我们往往可以在return之前进行assert直接退出,此时已经不需要return了
往年考试要写的检查precondition
throw 一个 IllegalArgumentException(信息)
几个题目
答案:ABD
解析:D选项不是 ClassNotFoiundException 异常,他是在运行阶段找不到class文件