如何写出漂亮的代码——不应有的返回值
项目中有下面这样一段代码,大家看有什么问题:
1 public class TemplateService 2 { 3 public Template Add(Template template) 4 { 5 //do save it to db 6 return template; 7 } 8 }
上面的代码我们可能经常都在写,好像看不出有什么问题。但我认为上面这个Add方法读起来就不通顺。如果代码是上面这么写的,那么调用的代码可能就像下面的这样:
var service = new TemplateService(); var template = new Template(){...}; template = service.Add(template);
注意到上面最后一行代码,读起来是不是非常别扭?
我认为好的代码应该是这样的:
1 var service = new TemplateService(); 2 var template = new Template(){...}; 3 service.Add(template);
(在Add方法体里面,可能会对template实例的某些属性进行赋值,比如ID,因此没有必要再返回template)。
其实,除了Add, 我认为还有很多方法都不应该带返回值。我可以随便列举一些非常常见的调用例子:
userService.Save(user);
userService.Update(user);
userService.Delete(user.Id);
userService.Login(user);
你可能会想,上面这些方法可以返回bool值啊。事实上,在很多代码里可以看到这些方法确实返回了bool值,甚至是有经验的程序员也在这么写。但我并不认为这是一种好的做法。对于那些返回bool值的方法(无非就是想告诉调用者方法是否执行成功),我认为应该用抛出异常的方式来处理。这样做有多个好处:
- 可以根据输入抛出多个不同的异常信息,而不是将异常吃掉,只是返回一个简单的true/false。
- 调用处的代码读起来更通顺。
对于某些方法如果你确实不想抛出详细的异常信息,只想告诉调用者成功与否,也就是说你的方法体里面自己会处理异常,那么我建议给方法名称加前缀“Try”. 然后你的代码就会变成这样:
var success = userService.TryLogin(username, password);
上面这段代码就告诉调用者不用处理异常了,因为service里面已经有try/catch了。如果使用抛出异常的模式,我也简单写个例子吧:
1 public void Login(username, password){ 2 var user = Get(username); 3 if(user == null){ 4 throw new Exception("The user doesn't exist"); 5 // throw new UserNotExistException(); 6 } 7 if(user.Password != EncodePassword(password)){ 8 throw new Exception("Incorrect password!"); 9 // throw new PasswordDosntMatchException(); 10 } 11 // do other logic 12 }
最后,我再举更多的那些不应该带返回值的方法调用例子:
1 var person = new Person(); 2 person.Talk(); 3 person.MoveTo(target.X, target.Y); 4 person.Go(); 5 6 var browser = new Browser(); 7 browser.Open(); 8 browser.Go(url); 9 browser.Close();
假如上面的这些方法带有返回值,你很难想象它们应该返回什么。
好了,本文就写到这里了。本文想说的是,想要写出漂亮的代码,那么你的代码读起来要朗朗上口。如果你有些不同意本文的观点,非常欢迎交流探讨。