java是一门面向对象的编程语言,那么,什么是面向对象编程?简单点说,就是找合适的对象办合适的事。举个生活中的例子,一个人想要开发一个程序,但是他不会编程,怎么办?他可以选择自己学编程,等学会了,再开发,这是面向过程的做法,特点就是什么都自己亲历亲为,对项目的把控性会比较好,但效率低下。另外一种做法就是,他自己不会编程,那就找一个会编程的人,帮他开发。这是面向对象的做法,特点是很多事并不是自己亲自做,而是找别人代做。这种做法,效率很高,但是对项目的把控性就会有所欠缺。很可能别人做出来的东西,并不是你想要的。
在java里面,应该怎么应用面向对象的编辑思想呢?比如,要做一个用户登录的功能,需求是用户名和密码都是8-16位,应该怎么做这个功能?很多开发人员,都是把用户名和密码的规则判断放到Controller里面,这其实是面向过程的做法。如果要用面向对象的做法,用户名和密码的规则判断,应该放到对象中去。可以定义一个User类,来接收前端传过来的用户名和密码。当我们定义了一个类,这个类的属性,能够接收什么样的数据,在类中就要定义好,这才是最好的逻辑。User类中有属性username,接收前端传过来的用户名,那么在User类的定义中,就可以限定username,必须是8-16位,这样,User类的实例,才是合适的对象。然后在Controller里面,就不需要做判断,把判断交给User类的对象去判断。这就是找合适的对象做合适的事。那么,在代码里,应该怎么来实现这样的功能?
package king;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
if(username == null){
return;
}
username = username.trim();
if("".equals(username)){
}else if(username.length()<8){
}else if(username.length()>16){
}else{
this.username = username;
}
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
if(password == null){
return;
}
password = password.trim();
if("".equals(password)){
}else if(password.length()<8){
}else if(password.length()>16){
}else{
this.password = password;
}
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}
这样,类的定义在set方法中就规定了username和password,能够接收什么样的数据,现在的问题是,在前面的那些异常数据的判断里,应该怎么处理?如果数据格式,不符合要求,那肯定要反馈给Controller的,再由Controller,反馈给前端去,怎么反馈?这个时候,就要用到异常机制,如果数据,不符合要求,那就抛出一个异常,但这个异常,和程序中其它的异常又是不一样的,所以这个异常,就应该使用自定义的异常。
package king;
public class KingException extends Exception {
private static final long serialVersionUID = 1L;
public KingException(){
super();
}
public KingException(String message){
super(message);
}
}
这样,就有了一个自定义的异常了。然后,在User类的set方法里面,数据不符合要求,就抛出这个异常,代码:
package king;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) throws KingException {
if(username == null){
throw new KingException("非法请求!");
}
username = username.trim();
if("".equals(username)){
throw new KingException("用户名不能为空!");
}else if(username.length()<8){
throw new KingException("用户名不能少于8位!");
}else if(username.length()>16){
throw new KingException("用户名最多只能有16位!");
}else{
this.username = username;
}
}
public String getPassword() {
return password;
}
public void setPassword(String password) throws KingException {
if(password == null){
throw new KingException("非法请求!");
}
password = password.trim();
if("".equals(password)){
throw new KingException("密码不能为空!");
}else if(password.length()<8){
throw new KingException("密码不能少于8位!");
}else if(password.length()>16){
throw new KingException("密码最多只能有16位!");
}else{
this.password = password;
}
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}
那么,在Controller里面,为User类的对象赋值的时候,就要捕获这个异常,然后调用异常的getMessage()方法,把异常的提示语,响应到前端去。
在类中判断数据规则,相比在Controller里面做判断,有什么好处呢?好处,就是代码量会减少,也更好维护。在对象中判断,不但能阻止前端传入的错误数据,也能阻止数据库中错误的数据,进入程序,而且不用重复写代码。如果是写在Controller里面,那么注册帐号,登录,修改密码等,几个接口里面,都要写一套判断逻辑,这就会产生大量的重复代码。而一旦规则更改了,则要修改好几个地方,一不小心,就漏掉一个地方没有修改。想想都觉得可怕!
再来看一个问题,很多时候,我们调用方法,是通过反射来调用的,那么,通过反射调用方法,如何获取方法本身抛出的异常,这个其实也很简单
package king;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Controller {
public static void main(String[] args) {
test();
}
public static void test(){
User user = new User();
Class<User> clazz = User.class;
Method method;
try {
method = clazz.getMethod("setUsername", String.class);
method.invoke(user, "123");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if(t instanceof KingException){
System.out.println(t.getMessage());
}
}
}
}
重点就在最后面的一个catch里面,通过e.getTargetException(),获取方法本身抛出的异常,先判断一下,如果异常的类型与KingException相符,那么就可以做相应的处理了。如果不相符,那就是程序抛出的其它异常了,这个就可能是程序的bug了,当然,我这里,没有写else分支。执行程序,就会打印:用户名不能少于8位!
再来看用于对象和json转换的jackson包,在对象和json转换的时候,如何获取方法本身的异常
package king;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Controller {
public static void main(String[] args) throws KingException {
String json = "{\"username\":\"1223\",\"password\":\"32651\"}";
ObjectMapper mapper = new ObjectMapper();
try {
User user = mapper.readValue(json, User.class);
System.out.println(user);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
Throwable t = e.getCause();
if(t instanceof KingException){
throw (KingException) t;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里,重点就在倒数第二个catch里面,通过e.getCause()方法,来获取方法自身抛出的异常。
了解了这一些,是不是可以去封装一些属于自己的方法了呢?
欢迎加入测试群:91425817,一起讨论测试的那此事。