天天看點

如何提高代碼的品質

 廢話在前:隻有總結,才能進步。

近日有人問起,“你認為如何能提高代碼的品質”,雖然都說出來了,但缺乏條理,特總結于此。

首先,應明确什麼樣的代碼算是品質高的。然後才能知道如何去做。

我覺得,高品質的代碼應該至少包括:

1.可讀性。

2.可維護性。

代碼的可讀性同樣有助于代碼的可維護性。有時候在一個項目裡,你修改的代碼未必是自己寫的,如果代碼寫的可讀性很差,那将是非常痛苦的。

一、可讀性

1.包名、類名、成員變量名、方法名、局部變量名等的命名應仔細斟酌。盡量做到讀一段代碼,就像是讀一句話一樣,在閱讀的過程中就能了解其中的邏輯。

2.包下面應包含哪些類,這也是有講究的。不能太随意。從包中應該可以大概看出類的功能或所在層次。

3.一個方法隻要實作一個功能。這一點很重要,首先利于閱讀,方法的名字可以告訴你它的功能。

4.方法的實作不宜過長,個人寫代碼的習慣是,一個方法的長度不會超過電腦的一屏。也就是不用拖動滾動條便可把實作盡收眼底。

二、可維護性

1.代碼寫的要靈活,尤其是一些配置檔案。比如寫一個下載下傳程式,檔案的放置路徑就不能在代碼中寫死。因為一來以後要變動的話,還要來改程式,并重新部署;二來開發的環境與正式的環境有所不同,寫死也不利于部署。

最典型的例子就是資料庫的連接配接資訊,url、使用者名、密碼等,開發環境與正式環境一般不會相同,把這些資訊寫在配置檔案裡為好。

2.提高的代碼複用,以提高代碼的維護性。

舉個反例吧。我們的系統中有很多生成Excel檔案并在浏覽器端下載下傳的功能要求,由于這些功能由不同的人來完成,結果類似的程式寫了二十幾份,都是互相拷貝而來。

當時我們用的是POI的低版本,後來進行了POI的更新,有一些API不能使用了,于是改了二十幾個類。如果把這些功能複用一些,也許隻要修改一個類檔案就搞定了。

3.多用一些設計模式,提高代碼的層次感。使得修改代碼的時候,影響範圍達到盡量的小。這個就有難度了。平時要慢慢積累才行。

常用的模式 工廠模式、模闆模式、擴充卡模式、政策模式、代理模式(動态代理) 等。這些模式在平時的工作中經常用到,應該熟練運用才行。

下面是一些代碼片段:

private void checkJob(JobConfig job) {

JobConfig original = find(job);

if (original != null) { // 已存在的任務 進行替換

if (original.equals(job)) { // 任務沒有變更

} else if (replace(original, job)) { // 替換作業成功 則加入到新作業清單中

allJobs.remove(original);

}

} else if (schedule(job)) { // 新添加的任務

log.info(Log4jHelper.getLogMain(job) + "派發成功。");

}

}

private JobConfig find(JobConfig job) {

for (JobConfig j : allJobs) {

// 找到相同作業ID的任務

if (j.getJobId().equals(job.getJobId())) {

return j;

}

}

return null;

}

private boolean replace(JobConfig original, JobConfig job) {

return remove(original) && schedule(job);

}

private boolean remove(JobConfig job) {

try {

return schedulerService.remove(job);

}

catch (SchedulerException e) {

e.printStackTrace();

log.error(Log4jHelper.getLogMain(job) + "移除失敗。");

}

return false;

}

private boolean schedule(JobConfig job) {

try {

schedulerService.schedule(job);

}

catch (Exception e) {

e.printStackTrace();

log.error(Log4jHelper.getLogMain(job) + "派發失敗。");

return false;

}

return true;

}

import java.io.IOException;

import java.io.InputStream;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.lang.reflect.ParameterizedType;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import org.apache.commons.collections.Predicate;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;

import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import org.springframework.core.type.classreading.CachingMetadataReaderFactory;

import org.springframework.core.type.classreading.MetadataReader;

import org.springframework.core.type.classreading.MetadataReaderFactory;

import com.lim.base.exception.AppException;

/**

* A collection of class management utility methods.

*

*/

@SuppressWarnings("unchecked")

public class ClassUtils {

/**

* 獲得泛型類泛型參數類型.

* 例如:

* getGenericArgumentsType(List<String>.class)傳回Class<String>.

* @param <T>

* @param cls

* @return

*/

public static <T> Class<T> getGenericArgsType(Class<?> cls) {

return getGenericArgumentsType(cls, 0);

}

/**

* 獲得泛型類泛型參數類型.

* @param <T>

* @param cls

* @param pos

* @return

*/

public static <T> Class<T> getGenericArgumentsType(Class<?> cls, int pos) {

return (Class<T>) ((ParameterizedType) cls.getGenericSuperclass()).getActualTypeArguments()[pos];

}

/**

* 在指定的類路徑查找符合條件的類.<br/>

* @param classPathPattern

* @param predicate

* @return

*/

public static Class<?>[] getClasses(String classPathPattern, Predicate predicate) {

PathMatchingResourcePatternResolver resolver = null;

resolver = new PathMatchingResourcePatternResolver();

MetadataReaderFactory metaFactory = null;

metaFactory = new CachingMetadataReaderFactory(resolver);

try {

Resource[] resources = resolver.getResources("classpath*:" + classPathPattern);

ArrayList<Class<?>> clazzArr = new ArrayList<Class<?>>();

for (Resource res : resources) {

if (!res.isReadable()) {

continue;

}

MetadataReader metadataReader = metaFactory.getMetadataReader(res);

String className = metadataReader.getClassMetadata().getClassName();

Class<?> clazz = ClassUtils.loadClass(className);

if (predicate.evaluate(clazz)) {

clazzArr.add(clazz);

}

}

return clazzArr.toArray(new Class<?>[0]);

}

catch (IOException e) {

throw new AppException(e);

}

catch (LinkageError e) {

throw new AppException(e);

}

}

/**

* 在指定的類路徑查找指定父類/接口類的所有子類.

* Example:

* Class<ITagChecker>[] checkerClz = ClassUtils.getSubClasses("com/linkage/ess/**<pre>/*</pre>.class", ITagChecker.class);

* @param <T>

* @param classPathPattern

* @param superClass

* @return

*/

public static <T> Class<? extends T>[] getSubClasses(String classPathPattern,

final Class<T> superClass) {

return (Class<? extends T>[]) getClasses(classPathPattern, new Predicate() {

@Override

public boolean evaluate(Object arg0) {

Class<?> clazz = (Class<?>) arg0;

return !clazz.isInterface() && superClass.isAssignableFrom(clazz);

}

});

}

/**

* Create a new instance given a class name(要求有預設構造函數).

*

* @param className

* A class name

* @return A new instance

* @throws ClassNotFoundException

* @throws IllegalAccessException

* @throws InstantiationException

* @exception Exception

* If an instantiation error occurs

*/

public static <T> T newInstance(Class<T> clz) {

try {

return clz.newInstance();

}

catch (InstantiationException e) {

e.printStackTrace();

throw new AppException(e);

}

catch (IllegalAccessException e) {

e.printStackTrace();

throw new AppException(e);

}

}

/**

* 帶有參數的執行個體建立.

* @param <T>

* @param impl

* @param param

* @param params

* @return

*/

public static <T> T newInstance(Class<T> impl, Object... params) {

List<Class<?>> lstClass = new ArrayList<Class<?>>(params.length + 1);

for (Object obj : params) {

lstClass.add(obj.getClass());

}

Class<?> paramClasses[] = lstClass.toArray(new Class<?>[0]);

return newInstance(impl, paramClasses, params);

}

/**

* 帶有參數的執行個體建立.

* @param <T>

* @param impl

* @param paramClasses

* @param params

* @return

*/

public static <T> T newInstance(Class<T> impl, Class<?> paramClasses[], Object params[]) {

try {

Constructor<T> constructor = impl.getConstructor(paramClasses);

return constructor.newInstance(params);

}

catch (InstantiationException e) {

e.printStackTrace();

throw new AppException(e);

}

catch (IllegalAccessException e) {

e.printStackTrace();

throw new AppException(e);

}

catch (IllegalArgumentException e) {

throw new AppException(e);

}

catch (InvocationTargetException e) {

throw new AppException(e);

}

catch (SecurityException e) {

throw new AppException(e);

}

catch (NoSuchMethodException e) {

throw new AppException(e);

}

}

/**

* 使用類型的執行個體建立.(要求有預設構造函數).

* @param className

* @return

*/

public static Object newInstance(String className) {

try {

return loadClass(className).newInstance();

}

catch (InstantiationException e) {

e.printStackTrace();

throw new AppException(e);

}

catch (IllegalAccessException e) {

e.printStackTrace();

throw new AppException(e);

}

}

/**

* Load a class given its name. BL: We wan't to use a known

* ClassLoader--hopefully the heirarchy is set correctly.

*

* @param className

* A class name

* @return The class pointed to by <code>className</code>

* @exception ClassNotFoundException

* If a loading error occurs

*/

public static Class<?> loadClass(String className) {

try {

return getClassLoader().loadClass(className);

}

catch (ClassNotFoundException e) {

throw new AppException(e);

}

}

public static Method getMethod(String className, String name, Class<?>... parameterTypes) {

return getMethod(loadClass(className), name, parameterTypes);

}

public static Method getMethod(Class<?> cls, String name, Class<?>... parameterTypes) {

try {

return cls.getMethod(name, parameterTypes);

}

catch (SecurityException e) {

throw new AppException(e);

}

catch (NoSuchMethodException e) {

throw new AppException(e);

}

}

/**

* Return a resource URL. BL: if this is command line operation, the

* classloading issues are more sane. During servlet execution, we

* explicitly set the ClassLoader.

*

* @return The context classloader.

* @exception MalformedURLException

* If a loading error occurs

*/

public static URL getResource(String resource) {

return getClassLoader().getResource(resource);

}

public static InputStream loadResource(String path) {

try {

return new ClassPathResource(path).getInputStream();

}

catch (IOException e) {

e.printStackTrace();

throw new AppException(e);

}

}

/**

* Return the context classloader. BL: if this is command line operation,

* the classloading issues are more sane. During servlet execution, we

* explicitly set the ClassLoader.

*

* @return The context classloader.

*/

public static ClassLoader getClassLoader() {

return Thread.currentThread().getContextClassLoader();

}

public static Field getDeclaredField(Class<?> cls, String fieldName) {

try {

return cls.getDeclaredField(fieldName);

}

catch (Exception e) {

throw new AppException(e);

}

}

public static Object invokeQuietly(Object target, Method m) {

try {

return m.invoke(target);

}

catch (IllegalArgumentException e) {

e.printStackTrace();

}

catch (IllegalAccessException e) {

e.printStackTrace();

}

catch (InvocationTargetException e) {

e.printStackTrace();

if (e.getTargetException() instanceof RuntimeException) {

throw (RuntimeException) e.getTargetException();

}

}

return null;

}

}