欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 java 怎么使用 设计模式对业务进行解耦(一)

程序员文章站 2022-04-01 18:49:40
最近非常头疼 ,到新公司碰到了 非常没有经验的产品,感觉产品经理和说相声一样,门槛很低,进了门才发现 楼梯在门里面,一层比一层难爬我是做Android开发的,目前还是使用java 作为开发语言,所以以java为例,归纳一下我的java 使用经验移动端的社交分享功能大家应该都用过,有一些公司早就 提供了免费的社交分享集成SDK,比如友盟,shareSdk为什么 已经有了 集成好的sdk 还会头疼呢,因为产品在 一个简单的分享功能上强行制造了 非常多逻辑分支,思维导图如下(还是我 为了抽象代码自己画的,产...

最近非常头疼 ,到新公司碰到了 非常没有经验的产品,感觉产品经理这个职业和郭德纲评价相声一样,职业门槛很低,进了门才发现 楼梯在门里面,一层比一层难爬

我是做Android开发的,目前还是使用java 作为开发语言,所以以java为例,归纳一下我的java 使用经验

移动端的社交分享功能大家应该都用过,有一些公司早就 提供了免费的社交分享集成SDK,比如友盟,shareSdk

为什么 已经有了 集成好的sdk 还会头疼呢,因为产品在 一个简单的分享功能上强行制造了 非常多逻辑分支,思维导图如下(还是我 为了抽象代码自己画的,产品没有这种能力)

荐
                                                        java 怎么使用 设计模式对业务进行解耦(一)
你可以看到 ,有一些要求分享小程序,有一些要求分享h5,还有 类似淘口令、海报的分享

分享形式和分享业务 横竖组成的逻辑分支 是非常多的,只写if-else 肯定是非常混乱和难以维护的

所以我想到了使用 设计模式来 对这些逻辑 进行抽象

怎么创建 组件对象呢

  1. 如上图 可以看出,不同的业务 分享的参数是不一样的,所以用单例模式是不合理的

  2. 分享需要的字段还是很多的,还面临这 增加的情况,所以我在创建 创建分享组件对象的时候 使用了 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 需要的参数呢,这中间有一系列的字符串转换操作

我选用了 策略设计模式,转换的操作 抽象出来可以 分为

  1. 类型判断判断出 是否要从 shareUrl中解析 参数,(因为有web js交互,规则订的很烦)
  2. 生成 淘口令
  3. 生成 小程序码

抽象出接口

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

相关标签: java 设计模式