如何写好代码
前言
最近在接手别人的项目,看人家的代码是痛苦的,尤其是写的不怎么样的代码。想到之前看了一本《代码整洁之道》,对我影响深远,便想作此文舒缓一下心情。
如果你是大牛请忽略本文。
什么是好代码
书中说:好的代码就是它恰好为解决某一问题而存在。
听人说:好的代码就是给一个应届毕业生也可以看懂。
我现在深深的秉承 单一职责原则,就这一条足以写出我认为漂亮的代码。
作为一个无名小卒,为了梦想,就算为了后人能看懂,必须好好写代码。
好代码是什么样子的
举个抽象的例子,如果代码写成这样,把所有的逻辑按照顺序都堆砌在这个方法中,那么这段代码或许思路清晰,路径考虑周全,效率非常高,但是这并不算好的代码。
public class MechandiseManager{
private static final Integer TYPE_ONE = 1;
private static final String CODE_EXAMPLE_DELICIOUS = "delicious";
private static final String MAP_KEY_EXAMPLE = "key";
private static volatile boolean running = false;
@Autowired
private static SomeService someService;
public static GoodsParam setGoodParam(String code,Integer id, Float price, Integer type) throws Exception{
GoodsParam goodParam = new FoodParam();
goodParam.setCode(code);
goodParam.setXXId(id);
if(type.equals("1")){
if(){
//shit mass
}else{
//shit mass
}
for(int i=0;i<SOME;i++){
map.get("field1");
}
}else{
String val = someDataMap.get(obj.getSomeField());
if(val==SOME || ((CONDITION2)&&(CONDITION3))){
//shit mass
Data data = someService.selectSomeData();
for(){
}
}else{
//shit mass
if(){
}
}
}
if(){
//businsess
}
return goodParam ;
}
}
分析代码
代码中if条件语义不是非常人性化,分支混乱,本来是处理Goods的参数的,混杂太多条件,写的人或许过一段时间再来,就看的云里雾里,更别指望别人来给他改BUG。不过,该代码值得参考的地方在于设置了一些可读性强的常量。
改进代码
public static GoodsParam setGoodParam(String code,Integer id, Float price, Integer type) throws Exception{
GoodsParam goodParam = new FoodParam();
goodParam.setCode(code);
goodParam.setXXId(id);
if(type.equals(TYPE_ONE)){
processSomething(goodParam);
}else{
String val = someDataMap.get(MAP_KEY_EXAMPLE);
processAnotherThing(goodsParam,val);
}
if(){
//businsess
}
return goodParam ;
}
再次改进
public static GoodsParam setGoodParam(String code,Integer id, Float price, Integer type) throws Exception{
GoodsParam goodParam = new FoodParam();
goodParam.setCode(code);
goodParam.setXXId(id);
if(isTypeONE(type)){
processSomething(goodParam);
}else{
processAnotherThing(goodsParam,val);
}
thenProcessSomeThing();
return goodParam ;
}
public static boolean isTypeONE(Integer type){
return type.equals(TYPE_ONE);
}
终极改进
public static GoodsParam setGoodParam(String code,Integer id, Float price, Integer type) throws Exception{
GoodsParam goodParam = new FoodParam();
goodParam.setCode(code);
goodParam.setXXId(id);
processType(goodParam );
thenProcessSomeThing();
return goodParam ;
}
多学习开源项目
以下节选自Spring框架的内部源码:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
再看一个DispatcherServlet的源码:
protected void onRefresh(ApplicationContext context) throws BeansException {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize
* further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
}
有没有觉得非常清晰,一步一步,非常震撼,当时见到的时候真的觉得自己写的代码写的就是Shit…
总结
个人总结:写代码并不是一下子就能写出那么漂亮而简洁的代码,在写的过程中,要像写文章一样思考,而不是记流水账一样,想到哪里就写到哪里,先把逻辑写完,然后回顾代码,看看能不能把那些分支,循环尽可能简化,例如把每一个判断都尽可能让人看懂,用一个函数表达他的含义,这样函数调用函数,层次分明,看着就知道哪一步是做什么,哪一步又需要处理什么,一目了然。以后再查看自己的代码或者别人维护你的代码时,自顶向下,由主干要枝叶,条理清晰,神清气爽。
在下无名小卒,但愿能 make you impressive.