荐 java 怎么使用 设计模式对业务进行解耦(一)
最近非常头疼 ,到新公司碰到了 非常没有经验的产品,感觉产品经理这个职业和郭德纲评价相声一样,职业门槛很低,进了门才发现 楼梯在门里面,一层比一层难爬
我是做Android开发的,目前还是使用java 作为开发语言,所以以java为例,归纳一下我的java 使用经验
移动端的社交分享功能大家应该都用过,有一些公司早就 提供了免费的社交分享集成SDK,比如友盟,shareSdk
为什么 已经有了 集成好的sdk 还会头疼呢,因为产品在 一个简单的分享功能上强行制造了 非常多逻辑分支,思维导图如下(还是我 为了抽象代码自己画的,产品没有这种能力)
你可以看到 ,有一些要求分享小程序,有一些要求分享h5,还有 类似淘口令、海报的分享
分享形式和分享业务 横竖组成的逻辑分支 是非常多的,只写if-else 肯定是非常混乱和难以维护的
所以我想到了使用 设计模式来 对这些逻辑 进行抽象
怎么创建 组件对象呢
-
如上图 可以看出,不同的业务 分享的参数是不一样的,所以用单例模式是不合理的
-
分享需要的字段还是很多的,还面临这 增加的情况,所以我在创建 创建分享组件对象的时候 使用了 builder 设计模式
优点 可以看Java 当构造方法参数过多时使用 builder 模式
shareSdk 需要的参数 可以放到一个类中 管理
public class ShareParams {
/**
* 分享 来源类型
* 从商品中 url分享 出
*/
public final static String SHARE_FROM_TYPE_URL = "url";
/**
* 分享 来源类型
* 从直播中分享 出
*/
public final static String SHARE_FROM_TYPE_LIVE = "live";
/**
* 弹窗吊起 类型
*/
public final static int TYPE_FROM_GOODS_LIST = 4001;
// public final static int TYPE_FROM_GOODS_DETAIL = 4002;
public final static int TYPE_FROM_BANNER_WEB = 4003;
public final static int TYPE_FROM_LIVE = 4004;
public final static int TYPE_FROM_STORE_ONEKEY = 4005;
public final static int TYPE_FROM_STORE_SHARE_OPEN = 4006;
public final static int WEB_TYPE_ALLPAGE = 5001;
public final static int WEB_TYPE_GOODS = 5002;
public final static int WEB_TYPE_LIVE = 5003;
public final static int IMAGE_TYPE_PATH = 1001;
public final static int IMAGE_TYPE_URL = 1002;
/**
* dialog 类型,不含 二维码分享
*/
public static int TYPE_NOQRCODE = 1;
/**
* dialog 类型,含有 二维码分享
*/
public static int TYPE_HASQRCODE = 2;
public String goodsId;
public String title;
public String detail;
public String imageUrl;
public String shareUrl;
public String shareUser;
//复制链接 url
public String copyLinkUrl;
public String wechatMiniAppPath;
public String miniappScene;
public String miniappPage;
public String wechatMomentUrl;
public int webType;
public int typeFrom;
public int shareDialogType;
public int imageType;
@Override
public String toString() {
return "ShareParams{" +
"goodsId='" + goodsId + '\'' +
", title='" + title + '\'' +
", detail='" + detail + '\'' +
", imageUrl='" + imageUrl + '\'' +
", shareUrl='" + shareUrl + '\'' +
", shareUser='" + shareUser + '\'' +
", copyLinkUrl='" + copyLinkUrl + '\'' +
", wechatMiniAppPath='" + wechatMiniAppPath + '\'' +
", miniappScene='" + miniappScene + '\'' +
", miniappPage='" + miniappPage + '\'' +
", wechatMomentUrl='" + wechatMomentUrl + '\'' +
", webType=" + webType +
", typeFrom=" + typeFrom +
", shareDialogType=" + shareDialogType +
", imageType=" + imageType +
'}';
}
}
public static class Builder {
private ShareParams shareParams;
private ShareStringHandler shareStringHandler;
public Builder() {
shareParams = new ShareParams();
UserInfoBean userInfo = UserManager.getInstance().getUserInfo();
if (CheckUtils.isNotNull(userInfo) && !CheckUtils.isEmpty(userInfo.getId())) {
//默认 share user 就是 登录的用户
shareParams.shareUser = userInfo.getId();
}
//默认 分享的图片链接是 网络图片 url
shareParams.imageType = ShareParams.IMAGE_TYPE_URL;
}
public Builder setShareStringHandler(IShareStringStrategy strategy) {
this.shareStringHandler = new ShareStringHandler(strategy);
return this;
}
/**
* 分享 文字 title
*
* @param title title
* @return Builder
*/
public Builder setTitle(String title) {
this.shareParams.title = title;
return this;
}
/**
* 分享 商品id
*
* @param goodsId 商品id
* @return Builder
*/
public Builder setGoodsId(String goodsId) {
this.shareParams.goodsId = goodsId;
return this;
}
/**
* 分享 文字描述,详情
*
* @param detail detail
* @return Builder
*/
public Builder setDetail(String detail) {
this.shareParams.detail = detail;
return this;
}
/**
* 分享 图片地址
*
* @param shareImageUrl shareImage
* @return Builder
*/
public Builder setShareImage(String shareImageUrl) {
this.shareParams.imageUrl = shareImageUrl;
return this;
}
public Builder setImageType(int imageType) {
this.shareParams.imageType = imageType;
return this;
}
/**
* 分享 图片地址
*
* @param shareUrl shareUrl
* @return Builder
*/
public Builder setShareUrl(String shareUrl) {
this.shareParams.shareUrl = shareUrl;
return this;
}
/**
* 分享 吊起入口 ,类型
*
* @param typeFrom typeFrom
* @return Builder
*/
public Builder setTypeFrom(int typeFrom) {
this.shareParams.typeFrom = typeFrom;
return this;
}
/**
* 分享 userid
*
* @param userId userId
* @return Builder
*/
public Builder setShareUser(String userId) {
this.shareParams.shareUser = userId;
return this;
}
/**
* 分享 dialog 类型
*
* @param type type
* @return Builder
*/
public Builder setDialogType(int type) {
this.shareParams.shareDialogType = type;
return this;
}
public Builder setWechatMiniAppPath(String wechatMiniAppPath) {
this.shareParams.wechatMiniAppPath = wechatMiniAppPath;
return this;
}
public ShareManager build() {
shareStringHandler = new ShareStringHandler(ShareStringHandler.createStrategy(shareParams.typeFrom));
if (CheckUtils.isNull(shareStringHandler)) {
throw new NullPointerException(TAG + " build error shareStringHandler null");
}
//不同类型 可能有 差异化操作,这个取决于 产品,产品水平差 ,逻辑抽象难
switch (this.shareParams.typeFrom) {
case ShareParams.TYPE_FROM_GOODS_LIST:
break;
case ShareParams.TYPE_FROM_BANNER_WEB:
shareStringHandler.getParamsFromString(shareParams);
break;
}
this.shareParams.shareUrl = shareStringHandler.shareUrl(shareParams);
shareStringHandler.shareCopyUrl(shareParams);
shareStringHandler.wechatMiniAppPath(shareParams);
return new ShareManager(this);
}
}
在使用的组件的时候 就非常方便了
new ShareManager.Builder()
.setGoodsId(item.getId())
.setTitle(item.getShareTitle())
.setDetail(item.getShareDesc())
.setShareImage(imageUrl)
.setDialogType(ShareParams.TYPE_HASQRCODE)
.setTypeFrom(ShareParams.TYPE_FROM_GOODS_LIST)
.build()
.showDialog(this);
这样就算有不同维度 的逻辑,只需要 加个参数,就可以了
根据不同的参数创建对象成功了,怎么根据参数 生成ShareSDK 需要的参数呢,这中间有一系列的字符串转换操作
我选用了 策略设计模式,转换的操作 抽象出来可以 分为
- 类型判断判断出 是否要从 shareUrl中解析 参数,(因为有web js交互,规则订的很烦)
- 生成 淘口令
- 生成 小程序码
抽象出接口
public interface IShareStringStrategy {
/**
* 把 参数转换成,分享点击跳转的 urlH
*
* @param shareParams shareParams
* @return String
*/
public String shareUrl(ShareParams shareParams);
/**
* 把 分享链接转换成 参数
* 在web js 交互时可使用
*
* @return ShareParams
*/
public void getParamsFromString(ShareParams shareParams);
public void wechatMiniAppPath(ShareParams shareParams);
}
具体实现 会根据 typeFrom 找到
public class GoodsStrategy implements IShareStringStrategy {
private static final String TAG = "GoodsStrategy:";
public static final String WECART_MINIAPP_SHARE_GOODS_URL = "/pages/goods_detail/goods_detail?id=";
public static final String WECART_MINIAPP_QRCODE_SHARE_GOODS_URL = "pages/goods_detail/goods_detail";
public static final String WECART_MOMENT_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx85cedb782a15233b&redirect_uri=%s&response_type=code&scope=snsapi_base&state=998#wechat_redirect";
private final String PARAM_UID = "&uid=";
private final String PARAM_ID = "id=";
@Override
public String shareUrl(ShareParams shareParams) {
StringBuffer buffer = new StringBuffer();
buffer.append(HttpConstants.BASE_URL)
.append(WebLoaderManager.H5_SHARE_GOODS_URL)
.append(shareParams.goodsId)
.append(PARAM_UID)
.append(shareParams.shareUser);
String url = buffer.toString();
Logger.d(TAG + " shareUrl " + url);
return url;
}
@Override
public void getParamsFromString(ShareParams shareParams) {
//不能 从 里面 ,解析参数
}
@Override
public void wechatMiniAppPath(ShareParams shareParams) {
StringBuffer buffer = new StringBuffer();
buffer.append(WECART_MINIAPP_SHARE_GOODS_URL)
.append(shareParams.goodsId)
.append(PARAM_UID)
.append(shareParams.shareUser);
shareParams.miniappPage = WECART_MINIAPP_QRCODE_SHARE_GOODS_URL;
shareParams.miniappScene = PARAM_ID + shareParams.goodsId + PARAM_UID + shareParams.shareUser;
shareParams.wechatMiniAppPath = buffer.toString();
shareParams.wechatMomentUrl = String.format(WECART_MOMENT_URL, EncodingUtil.encodeURIComponent(shareParams.shareUrl));
Logger.d(TAG + " wechatMiniAppPath " + shareParams.wechatMiniAppPath);
}
}
public class ShareStringHandler {
private static final String TAG = "ShareStringHandler:";
private static final Map<Integer, StrategyGenerator> strategys = new HashMap<>();
/**
* 需要分享的类型 ,必须在这里 注册,每个 生成 分享参数的 strategy
*/
static {
registerStrategy(ShareParams.TYPE_FROM_GOODS_LIST, () -> new GoodsStrategy());
registerStrategy(ShareParams.TYPE_FROM_BANNER_WEB, () -> new WebStrategy());
registerStrategy(ShareParams.TYPE_FROM_LIVE, () -> new LiveStrategy());
registerStrategy(ShareParams.TYPE_FROM_STORE_ONEKEY, () -> new StoreStrategy());
registerStrategy(ShareParams.TYPE_FROM_STORE_SHARE_OPEN, () -> new InviteOpenShopStrategy());
}
private static void registerStrategy(int type, StrategyGenerator taskGenerator) {
strategys.put(type, taskGenerator);
}
public static IShareStringStrategy createStrategy(int type) {
Logger.d(TAG + "createStrategy() called with: type = [" + type + "]");
if (strategys.containsKey(type)) {
return strategys.get(type).generate();
}
return null;
}
private final IShareStringStrategy shareStringEngine;
public ShareStringHandler(IShareStringStrategy shareStringEngine) {
this.shareStringEngine = shareStringEngine;
}
public static ShareKeywords isMatchShareUrl(String copyText) {
if (!CheckUtils.isEmpty(copyText)) {
IKeywordsStrategy keywordsStrategy = KeywordsManager.createParseStrategy(copyText);
if (keywordsStrategy != null) {
Logger.d(TAG + " createParseStrategy has register");
return keywordsStrategy.isMatchCopy(copyText);
} else {
Logger.d(TAG + " createParseStrategy has not register");
}
}
return null;
}
public void shareCopyUrl(ShareParams shareParams) {
IKeywordsStrategy keywordsStrategy = KeywordsManager.createStrategy(shareParams.typeFrom);
if (keywordsStrategy != null) {
Logger.d(TAG + " createStrategy has register");
shareParams.copyLinkUrl = keywordsStrategy.getCopyLinkUrl(shareParams);
} else {
Logger.d(TAG + " createStrategy has not register");
shareParams.copyLinkUrl = shareParams.shareUrl;
}
}
public String shareUrl(ShareParams shareParams) {
return shareStringEngine.shareUrl(shareParams);
}
public void wechatMiniAppPath(ShareParams shareParams) {
shareStringEngine.wechatMiniAppPath(shareParams);
}
public void getParamsFromString(ShareParams shareParams) {
shareStringEngine.getParamsFromString(shareParams);
}
/**
* 拼凑 给小程序 的字符串参数,
* !!! 规则制定完全没有问过我 ,做这种 字符串拼接 的操作,真的是低能
*
* @param shareParams shareParams
* @return String
*/
public static String splitWebScene(ShareParams shareParams) {
UrlUtil.UrlEntity urlEntity = UrlUtil.parse(shareParams.shareUrl);
if (CheckUtils.isNotNull(urlEntity) && !CheckUtils.isEmpty(urlEntity.baseUrl)) {
String[] urls = urlEntity.baseUrl.split(UrlUtil.URL_SEPARATOR);
if (urls.length > 0) {
String[] urls2 = urls[urls.length - 1].split(UrlUtil.URL_SUFIX_HTML);
if (urls2.length > 0) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(urls2[0]);
if (urlEntity.params.containsKey(UrlUtil.URL_PARAMS_ID)) {
stringBuilder.append(UrlUtil.URL_QUESTIONMASK)
.append(urlEntity.params.get(UrlUtil.URL_PARAMS_ID));
} else {
stringBuilder.append(UrlUtil.URL_QUESTIONMASK)
.append("1");
}
if (urlEntity.params.containsKey(UrlUtil.URL_PARAMS_UID)) {
stringBuilder.append(UrlUtil.URL_AND)
.append(urlEntity.params.get(UrlUtil.URL_PARAMS_UID));
}
return stringBuilder.toString();
}
}
}
return "";
}
}
StrategyGenerator 是 策略实现类的生成器,可以通过 匿名内部类实现
public interface StrategyGenerator<T extends IShareStringStrategy> {
T generate();
}
最后在builder 构造器的 build方法 ,一步步调用 生成所需的参数
public ShareManager build() {
shareStringHandler = new ShareStringHandler(ShareStringHandler.createStrategy(shareParams.typeFrom));
if (CheckUtils.isNull(shareStringHandler)) {
throw new NullPointerException(TAG + " build error shareStringHandler null");
}
//不同类型 可能有 差异化操作,这个取决于 产品,产品水平差 ,逻辑抽象难
switch (this.shareParams.typeFrom) {
case ShareParams.TYPE_FROM_GOODS_LIST:
break;
case ShareParams.TYPE_FROM_BANNER_WEB:
shareStringHandler.getParamsFromString(shareParams);
break;
}
this.shareParams.shareUrl = shareStringHandler.shareUrl(shareParams);
shareStringHandler.shareCopyUrl(shareParams);
shareStringHandler.wechatMiniAppPath(shareParams);
return new ShareManager(this);
}
使用map 集合维护一个 映射,通过typeFrom 去找到 具体的策略实现类
大概实现思路就是这样
遵守的原则就是
1.单一职责原则
2.开放关闭原则
3.接口隔离原则
现在就算再新增多少 维度,数量,通过扩展的方式
再不修改之前的代码的情况下,可以实现功能
本文地址:https://blog.csdn.net/XAVI_2010/article/details/107669456