近日有人问起,“你认为如何能提高代码的质量”,虽然都说出来了,但缺乏条理,特总结于此。
首先,应明确什么样的代码算是质量高的。然后才能知道如何去做。
我觉得,高质量的代码应该至少包括:
1.可读性。
2.可维护性。
代码的可读性同样有助于代码的可维护性。有时候在一个项目里,你修改的代码未必是自己写的,如果代码写的可读性很差,那将是非常痛苦的。
一、可读性
1.包名、类名、成员变量名、方法名、局部变量名等的命名应仔细斟酌。尽量做到读一段代码,就像是读一句话一样,在阅读的过程中就能理解其中的逻辑。
2.包下面应包含哪些类,这也是有讲究的。不能太随意。从包中应该可以大概看出类的功能或所在层次。
3.一个方法只要实现一个功能。这一点很重要,首先利于阅读,方法的名字可以告诉你它的功能。
4.方法的实现不宜过长,个人写代码的习惯是,一个方法的长度不会超过电脑的一屏。也就是不用拖动滚动条便可把实现尽收眼底。
二、可维护性
1.代码写的要灵活,尤其是一些配置文件。比如写一个下载程序,文件的放置路径就不能在代码中写死。因为一来以后要变动的话,还要来改程序,并重新部署;二来开发的环境与正式的环境有所不同,写死也不利于部署。
最典型的例子就是数据库的连接信息,url、用户名、密码等,开发环境与正式环境一般不会相同,把这些信息写在配置文件里为好。
2.提高的代码复用,以提高代码的维护性。
举个反例吧。我们的系统中有很多生成Excel文件并在浏览器端下载的功能要求,由于这些功能由不同的人来完成,结果类似的程序写了二十几份,都是互相拷贝而来。
当时我们用的是POI的低版本,后来进行了POI的升级,有一些API不能使用了,于是改了二十几个类。如果把这些功能复用一些,也许只要修改一个类文件就搞定了。
3.多用一些设计模式,提高代码的层次感。使得修改代码的时候,影响范围达到尽量的小。这个就有难度了。平时要慢慢积累才行。
常用的模式 工厂模式、模板模式、适配器模式、策略模式、代理模式(动态代理) 等。这些模式在平时的工作中经常用到,应该熟练运用才行。
下面是一些代码片段:
1private void checkJob(JobConfig job) {
2 JobConfig original = find(job);
3 if (original != null) { // 已存在的任务 进行替换
4 if (original.equals(job)) { // 任务没有变更
5 } else if (replace(original, job)) { // 替换作业成功 则加入到新作业列表中
6 allJobs.remove(original);
7 }
8 } else if (schedule(job)) { // 新添加的任务
9 log.info(Log4jHelper.getLogMain(job) + "派发成功。");
10 }
11}
12
13private JobConfig find(JobConfig job) {
14 for (JobConfig j : allJobs) {
15 // 找到相同作业ID的任务
16 if (j.getJobId().equals(job.getJobId())) {
17 return j;
18 }
19 }
20 return null;
21}
22
23private boolean replace(JobConfig original, JobConfig job) {
24 return remove(original) && schedule(job);
25}
26
27private boolean remove(JobConfig job) {
28 try {
29 return schedulerService.remove(job);
30 }
31 catch (SchedulerException e) {
32 e.printStackTrace();
33 log.error(Log4jHelper.getLogMain(job) + "移除失败。");
34 }
35 return false;
36}
37
38private boolean schedule(JobConfig job) {
39 try {
40 schedulerService.schedule(job);
41 }
42 catch (Exception e) {
43 e.printStackTrace();
44 log.error(Log4jHelper.getLogMain(job) + "派发失败。");
45 return false;
46 }
47 return true;
48}
49
1import java.io.IOException;
2import java.io.InputStream;
3import java.lang.reflect.Constructor;
4import java.lang.reflect.Field;
5import java.lang.reflect.InvocationTargetException;
6import java.lang.reflect.Method;
7import java.lang.reflect.ParameterizedType;
8import java.net.MalformedURLException;
9import java.net.URL;
10import java.util.ArrayList;
11import java.util.List;
12
13import org.apache.commons.collections.Predicate;
14import org.springframework.core.io.ClassPathResource;
15import org.springframework.core.io.Resource;
16import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
17import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
18import org.springframework.core.type.classreading.MetadataReader;
19import org.springframework.core.type.classreading.MetadataReaderFactory;
20
21import com.lim.base.exception.AppException;
22
23/** *//**
24 * A collection of class management utility methods.
25 *
26 */
27@SuppressWarnings("unchecked")
28public class ClassUtils {
29
30 /** *//**
31 * 获得泛型类泛型参数类型.
32 * 例如:
33 * getGenericArgumentsType(List<String>.class)返回Class<String>.
34 * @param <T>
35 * @param cls
36 * @return
37 */
38 public static <T> Class<T> getGenericArgsType(Class<?> cls) {
39 return getGenericArgumentsType(cls, 0);
40 }
41
42 /** *//**
43 * 获得泛型类泛型参数类型.
44 * @param <T>
45 * @param cls
46 * @param pos
47 * @return
48 */
49 public static <T> Class<T> getGenericArgumentsType(Class<?> cls, int pos) {
50 return (Class<T>) ((ParameterizedType) cls.getGenericSuperclass()).getActualTypeArguments()[pos];
51 }
52
53 /** *//**
54 * 在指定的类路径查找符合条件的类.<br/>
55 * @param classPathPattern
56 * @param predicate
57 * @return
58 */
59 public static Class<?>[] getClasses(String classPathPattern, Predicate predicate) {
60 PathMatchingResourcePatternResolver resolver = null;
61 resolver = new PathMatchingResourcePatternResolver();
62 MetadataReaderFactory metaFactory = null;
63 metaFactory = new CachingMetadataReaderFactory(resolver);
64 try {
65 Resource[] resources = resolver.getResources("classpath*:" + classPathPattern);
66 ArrayList<Class<?>> clazzArr = new ArrayList<Class<?>>();
67 for (Resource res : resources) {
68 if (!res.isReadable()) {
69 continue;
70 }
71
72 MetadataReader metadataReader = metaFactory.getMetadataReader(res);
73 String className = metadataReader.getClassMetadata().getClassName();
74 Class<?> clazz = ClassUtils.loadClass(className);
75 if (predicate.evaluate(clazz)) {
76 clazzArr.add(clazz);
77 }
78 }
79 return clazzArr.toArray(new Class<?>[0]);
80 }
81 catch (IOException e) {
82 throw new AppException(e);
83 }
84 catch (LinkageError e) {
85 throw new AppException(e);
86 }
87 }
88
89 /** *//**
90 * 在指定的类路径查找指定父类/接口类的所有子类.
91 * Example:
92 * Class<ITagChecker>[] checkerClz = ClassUtils.getSubClasses("com/linkage/ess/**<pre>/*</pre>.class", ITagChecker.class);
93 * @param <T>
94 * @param classPathPattern
95 * @param superClass
96 * @return
97 */
98 public static <T> Class<? extends T>[] getSubClasses(String classPathPattern,
99 final Class<T> superClass) {
100
101 return (Class<? extends T>[]) getClasses(classPathPattern, new Predicate() {
102 @Override
103 public boolean evaluate(Object arg0) {
104 Class<?> clazz = (Class<?>) arg0;
105 return !clazz.isInterface() && superClass.isAssignableFrom(clazz);
106 }
107 });
108 }
109
110 /** *//**
111 * Create a new instance given a class name(要求有默认构造函数).
112 *
113 * @param className
114 * A class name
115 * @return A new instance
116 * @throws ClassNotFoundException
117 * @throws IllegalAccessException
118 * @throws InstantiationException
119 * @exception Exception
120 * If an instantiation error occurs
121 */
122 public static <T> T newInstance(Class<T> clz) {
123 try {
124 return clz.newInstance();
125 }
126 catch (InstantiationException e) {
127 e.printStackTrace();
128 throw new AppException(e);
129 }
130 catch (IllegalAccessException e) {
131 e.printStackTrace();
132 throw new AppException(e);
133 }
134
135 }
136
137 /** *//**
138 * 带有参数的实例创建.
139 * @param <T>
140 * @param impl
141 * @param param
142 * @param params
143 * @return
144 */
145 public static <T> T newInstance(Class<T> impl, Object params) {
146 List<Class<?>> lstClass = new ArrayList<Class<?>>(params.length + 1);
147 for (Object obj : params) {
148 lstClass.add(obj.getClass());
149 }
150 Class<?> paramClasses[] = lstClass.toArray(new Class<?>[0]);
151
152 return newInstance(impl, paramClasses, params);
153 }
154
155 /** *//**
156 * 带有参数的实例创建.
157 * @param <T>
158 * @param impl
159 * @param paramClasses
160 * @param params
161 * @return
162 */
163 public static <T> T newInstance(Class<T> impl, Class<?> paramClasses[], Object params[]) {
164 try {
165 Constructor<T> constructor = impl.getConstructor(paramClasses);
166 return constructor.newInstance(params);
167 }
168 catch (InstantiationException e) {
169 e.printStackTrace();
170 throw new AppException(e);
171 }
172 catch (IllegalAccessException e) {
173 e.printStackTrace();
174 throw new AppException(e);
175 }
176 catch (IllegalArgumentException e) {
177 throw new AppException(e);
178 }
179 catch (InvocationTargetException e) {
180 throw new AppException(e);
181 }
182 catch (SecurityException e) {
183 throw new AppException(e);
184 }
185 catch (NoSuchMethodException e) {
186 throw new AppException(e);
187 }
188 }
189
190 /** *//**
191 * 使用类型的实例创建.(要求有默认构造函数).
192 * @param className
193 * @return
194 */
195 public static Object newInstance(String className) {
196 try {
197 return loadClass(className).newInstance();
198 }
199 catch (InstantiationException e) {
200 e.printStackTrace();
201 throw new AppException(e);
202 }
203 catch (IllegalAccessException e) {
204 e.printStackTrace();
205 throw new AppException(e);
206 }
207 }
208
209 /** *//**
210 * Load a class given its name. BL: We wan't to use a known
211 * ClassLoader--hopefully the heirarchy is set correctly.
212 *
213 * @param className
214 * A class name
215 * @return The class pointed to by <code>className</code>
216 * @exception ClassNotFoundException
217 * If a loading error occurs
218 */
219 public static Class<?> loadClass(String className) {
220 try {
221 return getClassLoader().loadClass(className);
222 }
223 catch (ClassNotFoundException e) {
224 throw new AppException(e);
225 }
226 }
227
228 public static Method getMethod(String className, String name, Class<?> parameterTypes) {
229 return getMethod(loadClass(className), name, parameterTypes);
230 }
231
232 public static Method getMethod(Class<?> cls, String name, Class<?> parameterTypes) {
233 try {
234 return cls.getMethod(name, parameterTypes);
235 }
236 catch (SecurityException e) {
237 throw new AppException(e);
238 }
239 catch (NoSuchMethodException e) {
240 throw new AppException(e);
241 }
242 }
243
244 /** *//**
245 * Return a resource URL. BL: if this is command line operation, the
246 * classloading issues are more sane. During servlet execution, we
247 * explicitly set the ClassLoader.
248 *
249 * @return The context classloader.
250 * @exception MalformedURLException
251 * If a loading error occurs
252 */
253 public static URL getResource(String resource) {
254 return getClassLoader().getResource(resource);
255 }
256
257 public static InputStream loadResource(String path) {
258 try {
259 return new ClassPathResource(path).getInputStream();
260 }
261 catch (IOException e) {
262 e.printStackTrace();
263 throw new AppException(e);
264 }
265 }
266
267 /** *//**
268 * Return the context classloader. BL: if this is command line operation,
269 * the classloading issues are more sane. During servlet execution, we
270 * explicitly set the ClassLoader.
271 *
272 * @return The context classloader.
273 */
274 public static ClassLoader getClassLoader() {
275 return Thread.currentThread().getContextClassLoader();
276 }
277
278 public static Field getDeclaredField(Class<?> cls, String fieldName) {
279 try {
280 return cls.getDeclaredField(fieldName);
281 }
282 catch (Exception e) {
283 throw new AppException(e);
284 }
285 }
286
287 public static Object invokeQuietly(Object target, Method m) {
288 try {
289 return m.invoke(target);
290 }
291 catch (IllegalArgumentException e) {
292 e.printStackTrace();
293 }
294 catch (IllegalAccessException e) {
295 e.printStackTrace();
296 }
297 catch (InvocationTargetException e) {
298 e.printStackTrace();
299 if (e.getTargetException() instanceof RuntimeException) {
300 throw (RuntimeException) e.getTargetException();
301 }
302 }
303
304 return null;
305 }
306}
----2010年08月31日