浅谈代码重构与优化
前几天看到有一篇不错的文章减少该死的if-else嵌套,觉得写得很不错,整理了一下后准备在团队内部简单分享一下。
写在前面
大家在接手项目的时候,应该有遇到过下面这种结构的代码
if (true) {
.....
if (true) {
if (true) {
....
if (true) {
if (true) {
......
}
}
// do something
}
// do something
if (true) {
.........
}
}
// do something
}
看到这些代码,第一反应是脑壳痛,N多的if-else已经将这段代码的逻辑变得十分复杂,代码的可读性和可维护性也会变得极差。下面举个实际案例来介绍如何优化这种代码。
实际案例
业务需求:提供一个服务,可以让用户分享链接、图片、文本和图文,并将分享结果回调给用户。
初看这个业务很需求很简单,先写一个简单的demo
public class ShareItem {
public static final int TYPE_LINK = 0;
public static final int TYPE_IMAGE = 1;
public static final int TYPE_TEXT = 2;
public static final int TYPE_IMAGE_TEXT = 3;
public int type;
public String title;
public String content;
public String imagePath;
public String link;
}
public void share (ShareItem item, ShareListener listener) {
if (item != null) {
if (item.type == TYPE_LINK) {
// 分享链接
if (!StringUtils.isEmpty(item.link) && !StringUtils.isEmpty(item.title)) {
doShareLink(item.link, item.title, item.content, listener);
} else {
if (listener != null) {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
}
}
} else if (item.type == TYPE_IMAGE) {
// 分享图片
if (!StringUtils.isEmpty(item.imagePath)) {
doShareImage(item.imagePath, listener);
} else {
if (listener != null) {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
}
}
} else if (item.type == TYPE_TEXT) {
// 分享文本
if (!StringUtils.isEmpty(item.content)) {
doShareText(item.content, listener);
} else {
if (listener != null) {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
}
}
} else if (item.type == TYPE_IMAGE_TEXT) {
// 分享图文
if (!StringUtils.isEmpty(item.imagePath) && !StringUtils.isEmpty(item.content)) {
doShareImageAndText(item.imagePath, item.content, listener);
} else {
if (listener != null) {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
}
}
} else {
if (listener != null) {
listener.onCallback(ShareListener.STATE_FAIL, "不支持的分享类型");
}
}
} else {
if (listener != null) {
listener.onCallback(ShareListener.STATE_FAIL, "ShareItem 不能为 null");
}
}
}
上面这段代码,写完后好像没啥问题,至少思路是清晰的,但是如果经过几轮需求的摧残,这个代码可能就会变得很爆炸。比如说,新增了好几个分享方式,那if-else就会一直往下叠,更不用说如果产品来了一些定制化的需求,if-else里面就会再嵌if-else,最终极可能会得和最上面的代码例子一样了。
分层、卫语句
分层
接口分为外部和内部接口,所有空值判断放在外部接口完成,只处理一次;而内部接口传入的变量由外部接口保证不为空,从而减少空值判断。
Controller(简单校验) -> Service(核心业务处理) -> Data
Controller -> InternalService(简单校验) -> Service(核心业务处理) -> Data
卫语句
将异常流提前返回,好处是可以将异常流和正常流的代码分开,让开发人员将精力更聚焦在正常的业务流程上面,而且这种方式也能有效地较少if—else的嵌套层数。
if (a != null) {
// 正常流
} else {
// 异常流
}
if (a == null) {
// 异常流
return;
}
// 正常流
改造后的代码
public boolean share(ShareItem item, ShareListener listener) {
// 前置校验
if (listener == null) {
log.error("listener 不能为空!");
return false;
}
if (item == null) {
log.error("shareItem 不能为空!");
return false;
}
// 核心业务处理
shareProcess(item, listener);
return true;
}
public void shareProcess(ShareItem item, ShareListener listener) {
if (item.type == TYPE_LINK) {
// 分享链接
if (!StringUtils.isEmpty(item.link) && !StringUtils.isEmpty(item.title)) {
doShareLink(item.link, item.title, item.content, listener);
} else {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
}
} else if (item.type == TYPE_IMAGE) {
// 分享图片
if (!StringUtils.isEmpty(item.imagePath)) {
doShareImage(item.imagePath, listener);
} else {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
}
} else if (item.type == TYPE_TEXT) {
// 分享文本
if (!StringUtils.isEmpty(item.content)) {
doShareText(item.content, listener);
} else {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
}
} else if (item.type == TYPE_IMAGE_TEXT) {
// 分享图文
if (!StringUtils.isEmpty(item.imagePath) && !StringUtils.isEmpty(item.content)) {
doShareImageAndText(item.imagePath, item.content, listener);
} else {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
}
} else {
listener.onCallback(ShareListener.STATE_FAIL, "不支持的分享类型");
}
}
多态
利用多态,每种业务单独处理,在接口不再做任何业务判断。把ShareItem抽象出来,作为基础类,然后针对每种业务各自实现其子类:
public abstract class ShareItem {
public static final int TYPE_LINK = 0;
public static final int TYPE_IMAGE = 1;
public static final int TYPE_TEXT = 2;
public static final int TYPE_IMAGE_TEXT = 3;
public int type;
public ShareItem(int type) {
this.type = type;
}
public abstract boolean validate();
public abstract void doShare(ShareListener listener);
}
public class LinkShareItem extends ShareItem {
private String title;
private String content;
private String link;
public LinkShareItem(String title, String content, String link) {
super(TYPE_LINK);
this.title = title;
this.content = content;
this.link = link;
}
@Override
public boolean validate() {
return false;
}
@Override
public void doShare(ShareListener listener) {
// do share
}
}
public class ImageShareItem extends ShareItem {
private String imagePath;
public ImageShareItem(String imagePath) {
super(ShareItem.TYPE_IMAGE);
this.imagePath = imagePath;
}
@Override
public boolean validate() {
return false;
}
@Override
public void doShare(ShareListener listener) {
// do share
}
}
public class ImageTextShareItem extends ShareItem {
private String content;
private String imagePath;
public ImageTextShareItem(String content, String imagePath) {
super(ShareItem.TYPE_IMAGE_TEXT);
this.content = content;
this.imagePath = imagePath;
}
@Override
public boolean validate() {
return false;
}
@Override
public void doShare(ShareListener listener) {
// do share
}
}
public class TextShareItem extends ShareItem {
private String content;
public TextShareItem(String content) {
super(ShareItem.TYPE_TEXT);
this.content = content;
}
@Override
public boolean validate() {
return false;
}
@Override
public void doShare(ShareListener listener) {
// do share
}
}
将实现分离出来后,方法就变得很简洁了,if-else基本都已经被消除,以后如果新增一种分享方式,就只需要编写对应的实现方式就可以了。
public void share(ShareItem item, ShareListener listener) {
// 前置校验
if (listener == null) {
log.error("listener 不能为空!");
return;
}
if (item == null) {
log.error("shareItem 不能为空!");
return;
}
// 核心业务处理
shareProcess(item, listener);
}
public void shareProcess(ShareItem item, ShareListener listener) {
boolean validateRet = item.validate();
if (!validateRet) {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
return;
}
item.doShare(listener);
}
策略模式
上面的多态模式,是不是看上去已经很完美了?不过在我眼里其实不然,有一点不太合理的是,ShareItem作为POJO,里面不适应做过多的业务实现。目前贫血模式下,ShareItem应该作为一个BO,里面只放基础的属性值,而业务实现应该都放到各自的service里面。
这时候我们可以考虑使用策略模式对其进行优化。
将原ShareItem的业务逻辑代码移除,仅保留基础的属性
public abstract class ShareItem {
public static final int TYPE_LINK = 0;
public static final int TYPE_IMAGE = 1;
public static final int TYPE_TEXT = 2;
public static final int TYPE_IMAGE_TEXT = 3;
public int type;
}
public class ImageShareItem extends ShareItem {
private String imagePath;
}
public class ImageTextShareItem extends ShareItem {
private String content;
private String imagePath;
}
public class LinkShareItem extends ShareItem {
private String title;
private String content;
private String link;
}
public class TextShareItem extends ShareItem {
private String content;
}
编写策略类
public abstract class AbstractShareHandler {
public abstract boolean validate();
public abstract void doShare(ShareListener listener);
public abstract int getShareType();
}
@Service
public class ImageShareHandle extends AbstractShareHandler {
@Override
public boolean validate() {
return false;
}
@Override
public void doShare(ShareListener listener) {
}
@Override
public int getShareType() {
return ShareItem.TYPE_IMAGE;
}
}
@Service
public class ImageTextShareHandler extends AbstractShareHandler {
@Override
public boolean validate() {
return false;
}
@Override
public void doShare(ShareListener listener) {
}
@Override
public int getShareType() {
return ShareItem.TYPE_IMAGE_TEXT;
}
}
@Service
public class LinkShareHandler extends AbstractShareHandler {
@Override
public boolean validate() {
return false;
}
@Override
public void doShare(ShareListener listener) {
}
@Override
public int getShareType() {
return ShareItem.TYPE_LINK;
}
}
@Service
public class TextShareHandler extends AbstractShareHandler {
@Override
public boolean validate() {
return false;
}
@Override
public void doShare(ShareListener listener) {
}
@Override
public int getShareType() {
return ShareItem.TYPE_TEXT;
}
}
创建一个Manager类用来获取和管理策略
@Service
public class ShareManager implements InitializingBean, ApplicationContextAware {
/**
* 策略集合
*/
private Map<Integer, AbstractShareHandler> shareHandlerMap = new HashMap<>();
private ApplicationContext applicationContext;
/**
* 获取处理的策略
* @param shareType
* @return
*/
public AbstractShareHandler getHandler(Integer shareType) {
AbstractShareHandler shareHandler = shareHandlerMap.get(shareType);
if (shareHandler == null) {
throw new IllegalArgumentException("shareType handler not found, shareType=" + shareType);
}
return shareHandler;
}
@Override
public void afterPropertiesSet() {
// 自动注入策略
Map<String, AbstractShareHandler> shareImplMap = applicationContext.getBeansOfType(AbstractShareHandler.class);
for (AbstractShareHandler handler : shareImplMap.values()) {
shareHandlerMap.put(handler.getShareType(), handler);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
最后调整后的share方法就会变为下图那样
@Resource
private ShareManager shareManager;
public void share(ShareItem item, ShareListener listener) {
// 前置校验
if (listener == null) {
log.error("listener 不能为空!");
return;
}
if (item == null) {
log.error("shareItem 不能为空!");
return;
}
// 核心业务处理
shareProcess(item, listener);
}
private void shareProcess(ShareItem item, ShareListener listener) {
AbstractShareHandler handler = shareManager.getHandler(item.getType());
if (!handler.validate()) {
listener.onCallback(ShareListener.STATE_FAIL, "分享信息不完整");
return;
}
handler.doShare(listener);
}
至此,我们就用策略模式对这段代码进行了优化,看上去是不是比之前的版本好多了呢?
原文地址:https://www.cnblogs.com/miguel/p/10612477.html