策略模式的应用案例,以即时通信中,对不同类型的消息的构建处理业务为例,结合简单的缓存业务

       对于策略模式的概念,及优缺点,对于设计模式应用的应该都有所了解,这里暂不赘述,本文主要从应用实战的角度去处理。

      少啰嗦,先上图:

       在目前的即时通信中,消息的类型多种多样,对于不同的消息类型我们可能需要在不同的代码逻辑分支(if else判断)上去处理,并且随着消息类型的增加随,业务逻辑的扩展,会造成代码的臃肿,难以阅读,难以维护,这个时候我们可以想到的一种应用模式就是“策略模式”。

下面进入具体的应用代码示例:

package com.windfallsheng.strategypatterncase;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.windfallsheng.strategypatterncase.action.MsgHelper;
import com.windfallsheng.strategypatterncase.entity.MsgEntity;
import com.windfallsheng.strategypatterncase.util.TimeUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * @author lzsheng
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private final String TAG = "MainActivity";

    private int msgId;
    private int msgTextIndex;
    private int msgImgIndex;
    private int msgShareIndex;
    private Random r;
    private RecyclerView mRecyclerView;
    private MsgListAdapter mMsgListAdapter;
    private LinearLayoutManager mLinearLayoutManager;
    private List<MsgEntity> mMsgList;
    private TextView text, share, img;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRecyclerView = findViewById(R.id.recyclerview);
        text = findViewById(R.id.text);
        share = findViewById(R.id.share);
        img = findViewById(R.id.img);
        text.setOnClickListener(this);
        share.setOnClickListener(this);
        img.setOnClickListener(this);

        mLinearLayoutManager = new LinearLayoutManager(MainActivity.this);
        mRecyclerView.setLayoutManager(mLinearLayoutManager);
        mMsgListAdapter = new MsgListAdapter(MainActivity.this);
        mMsgList = new ArrayList<>();
        mMsgListAdapter.setMsgList(mMsgList);
        mRecyclerView.setAdapter(mMsgListAdapter);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.text: {
                String textJson = "{" +
                        "\"content\": \"这是第" + ++msgTextIndex + "条文本内容的消息\"" +
                        "}";
                MsgEntity msgEntity = buildMsgEntity(1, textJson);

                MsgEntity msg = MsgHelper.obtain().buildMsgObj(msgEntity);

                Log.d(TAG, "text:msg=" + msg.toString());
                addMsgAndRefresh(msg);
            }
            break;
            case R.id.share: {
                String shareJson = "{" +
                        "\"title\": \"这是第" + ++msgShareIndex + "条分享内容的消息\"," +
                        "\"desc\": \"这是我分享的内容,Just a little code farmer." +
                        "Just a little code farmer.Just a little code farmer.\"," +
                        "\"imgUrl\": \"我是\"" +
                        "}";
                MsgEntity msgEntity = buildMsgEntity(2, shareJson);

                MsgEntity msg = MsgHelper.obtain().buildMsgObj(msgEntity);

                Log.d(TAG, "share:msg=" + msg.toString());
                addMsgAndRefresh(msg);
            }
            break;
            case R.id.img: {
                String imgJson = "{" +
                        "\"desc\": \"这是第" + ++msgImgIndex + "条图片内容消息\"," +
                        "\"resUrl\": \"https://../../*.jpg\"," +
                        "\"type\": 1" +
                        "}";
                MsgEntity msgEntity = buildMsgEntity(3, imgJson);

                MsgEntity msg = MsgHelper.obtain().buildMsgObj(msgEntity);

                Log.d(TAG, "img:msg=" + msg.toString());
                addMsgAndRefresh(msg);
            }
            break;
            default:
                break;
        }
    }

    private void addMsgAndRefresh(MsgEntity msg) {
        mMsgList.add(msg);
        if (mMsgListAdapter != null) {
            mMsgListAdapter.notifyDataSetChanged();
        }
        if (mRecyclerView != null && mLinearLayoutManager != null) {
            int itemCount = mLinearLayoutManager.getItemCount();
            Log.d(TAG, "addMsgAndRefresh:itemCount=" + itemCount);
            mRecyclerView.scrollToPosition(itemCount - 1);
        }
    }

    /**
     * 模拟网络传输过来的不同类型的消息实例;
     *
     * @param json
     * @return
     */
    private MsgEntity buildMsgEntity(int msgType, String json) {
        if (r == null) {
            r = new Random();
        }
        int msgDirection = r.nextInt(2);
        Log.d(TAG, "msgDirection=" + msgDirection);
        String msgFrom;
        String msgto;
        if (msgDirection == 1) {
            // 发送的消息;
            msgFrom = "me";
            msgto = "friend";
        } else {
            // 接收的消息;
            msgFrom = "friend";
            msgto = "me";
        }
        return new MsgEntity(++msgId, msgType, json, null,
                msgFrom, msgto, msgDirection, 0, TimeUtils.getStrDate());
    }


}

buildMsgEntity();方法用来模拟网络传输过来的不同类型的消息实例;

根据网络传输过来的不同类型的消息,只需要按照如下的方式处理,就可以构建出来前端需要的消息实例;

MsgEntity msg = MsgHelper.obtain().buildMsgObj(msgEntity);

 

下面来看 MsgHelper 类是如何处理的:

package com.windfallsheng.strategypatterncase.action;

import android.util.Log;

import com.windfallsheng.strategypatterncase.builder.BaseMsgBuider;
import com.windfallsheng.strategypatterncase.builder.IMsgBuilder;
import com.windfallsheng.strategypatterncase.builder.MsgShareBuilder;
import com.windfallsheng.strategypatterncase.builder.MsgTextBuilder;
import com.windfallsheng.strategypatterncase.builder.MsgImgBuilder;
import com.windfallsheng.strategypatterncase.entity.MsgEntity;

/**
 * @author lzsheng
 */
public class MsgHelper {

    private final String TAG = "MsgHelper";

    /**
     * 当前实例的属性是否可重置,且实例可被重用,fase为不可用,true为可用;
     */
    public boolean flag;

    public MsgHelper() {
    }

    /**
     * 获取一个{@link MsgHelper}实例
     * <p>
     * 如果内存中的实例可被重用,则会返回内存中的实例对象,否则创建新实例;
     *
     * @return 返回一个可用的实例对象;
     */
    public static MsgHelper obtain() {
        MsgHelper msgHelper = (MsgHelper) CacheService.getInstance().getMsgCacheObj(MsgHelper.class);
//        MsgHelper msgHelper = new MsgHelper();
        return msgHelper;
    }

    public MsgHelper recycle() {
        this.flag = false;
        return this;
    }

    /**
     * 根据不同的消息类型,创建不同的消息构建者实例,
     * <p>
     * 如果这里的业务增多,也可以结合工厂方法模式处理不同对象的生成业务;
     *
     * @param msgType
     * @return
     */
    private IMsgBuilder initMsgBuilder(int msgType) {
        IMsgBuilder msgBuilder = null;
        switch (msgType) {
            case 1:
                msgBuilder = (IMsgBuilder) CacheService.getInstance().getMsgCacheObj(MsgTextBuilder.class);
//                msgBuilder = new MsgTextBuilder();
                break;
            case 2:
                msgBuilder = (IMsgBuilder) CacheService.getInstance().getMsgCacheObj(MsgShareBuilder.class);
//                msgBuilder = new MsgShareBuilder();
                break;
            case 3:
                msgBuilder = (IMsgBuilder) CacheService.getInstance().getMsgCacheObj(MsgImgBuilder.class);
//                msgBuilder = new MsgVoiceBuilder();
                break;
            default:
                break;
        }
        Log.d(TAG, "method:initMsgBuilder#return msgBuilder=" + msgBuilder);
        return msgBuilder;
    }

    /**
     * 创建消息构建者实例,并构建消息对象返回;
     *
     * @param msgEntity
     * @return
     */
    public MsgEntity buildMsgObj(MsgEntity msgEntity) {
        final IMsgBuilder msgBuilder = initMsgBuilder(msgEntity.getMsgType());
        if (msgBuilder == null) {
            return null;
        }
        final MsgEntity msgInfo = msgBuilder.buildMsgObj(msgEntity);
        synchronized (this) {
            // 当前实例对象任务已完成,将当前相关实例的的flag属性置为true,取可重用状态;
            ((BaseMsgBuider) msgBuilder).flag = true;
            flag = true;
            Log.d(TAG, "method:buildMsgObj#msgBuilder=" + msgBuilder);
            Log.d(TAG, "method:buildMsgObj#this=" + this);
            return msgInfo;
        }
    }

//    @Override
//    public String toString() {
//        return "MsgHelper{" +
//                "flag=" + flag +
//                '}';
//    }

}

可以看到,initMsgBuilder(); 方法根据不同的消息类型创建了不同的消息处理策略类,而它们都实现了统一的接口;

 

创建消息构建的接口,不同一消息类型处理类要实现这个统一的接口:

package com.windfallsheng.strategypatterncase.builder;


import com.windfallsheng.strategypatterncase.entity.MsgEntity;

/**
 * @author lzsheng
 * <p>
 * 构建不同类型消息实例的接口;
 */
public interface IMsgBuilder {

    public MsgEntity buildMsgObj(MsgEntity msgEntity);

}

我们定义了3种类型的消息处理策略类:

首先为不同消息的一些相同的处理业务定义一个抽象类;

package com.windfallsheng.strategypatterncase.builder;

/**
 * @author lzsheng
 * <p>
 * 增加一个简单的基类,用来处理共同的业务;
 */
public abstract class BaseMsgBuider implements IMsgBuilder {

    /**
     * 当前实例的属性是否可重置,且实例可被重用,fase为不可用,true为可用;
     */
    public boolean flag;

    public BaseMsgBuider recycle() {
        this.flag = false;
        return this;
    }

}

文本类型消息处理策略类:

package com.windfallsheng.strategypatterncase.builder;

import com.google.gson.Gson;
import com.windfallsheng.strategypatterncase.entity.MsgEntity;
import com.windfallsheng.strategypatterncase.entity.MsgTextBody;

/**
 * @author lzsheng
 * <p>
 * 在这里对不同的消息类型的处理业务只是简单的演示,实际情况要复杂;
 */
public class MsgTextBuilder extends BaseMsgBuider {

    @Override
    public MsgEntity buildMsgObj(MsgEntity msgEntity) {
        MsgTextBody msgTextBody = new Gson().fromJson(msgEntity.getMsgJson(), MsgTextBody.class);
        msgEntity.setMsgBody(msgTextBody);
        msgEntity.setMsgJson(null);
        // do something else.
        return msgEntity;
    }
}

分享类型消息处理策略类:

package com.windfallsheng.strategypatterncase.builder;

import com.google.gson.Gson;
import com.windfallsheng.strategypatterncase.entity.MsgEntity;
import com.windfallsheng.strategypatterncase.entity.MsgShareBody;

/**
 * @author lzsheng
 * <p>
 * 在这里对不同的消息类型的处理业务只是简单的演示,实际情况要复杂;
 */
public class MsgShareBuilder extends BaseMsgBuider {
    
    @Override
    public MsgEntity buildMsgObj(MsgEntity msgEntity) {
        MsgShareBody msgShareBody = new Gson().fromJson(msgEntity.getMsgJson(), MsgShareBody.class);
        msgEntity.setMsgBody(msgShareBody);
        msgEntity.setMsgJson(null);
        // do something else.
        return msgEntity;
    }
}

图片类型消息处理策略类:

package com.windfallsheng.strategypatterncase.builder;

import com.google.gson.Gson;
import com.windfallsheng.strategypatterncase.entity.MsgEntity;
import com.windfallsheng.strategypatterncase.entity.MsgImgBody;

/**
 * @author lzsheng
 * <p>
 * 在这里对不同的消息类型的处理业务只是简单的演示,实际情况要复杂;
 */
public class MsgImgBuilder extends BaseMsgBuider {

    @Override
    public MsgEntity buildMsgObj(MsgEntity msgEntity) {
        MsgImgBody msgImgBody = new Gson().fromJson(msgEntity.getMsgJson(), MsgImgBody.class);
        msgEntity.setMsgBody(msgImgBody);
        msgEntity.setMsgJson(null);
        // do something else.
        return msgEntity;
    }

}

 这里自己作了一个简单的对应用对象实例的缓存类,以便让频繁使用对象实例得以复用;

package com.windfallsheng.strategypatterncase.action;

import android.util.Log;

import com.windfallsheng.strategypatterncase.builder.BaseMsgBuider;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lzsheng
 * <p>
 * 这里的缓存策略可能根据业务需求处理;
 */
public class CacheService {

    private final String TAG = "CacheService";

    private ConcurrentHashMap CACHE = new ConcurrentHashMap();

    private static class SingletonHolder {
        static CacheService INSTANCE = new CacheService();
    }

    public static CacheService getInstance() {
        return SingletonHolder.INSTANCE;
    }

    public void cacheObj(Object o) {
        String clazzName = o.getClass().getName();
        Log.d(TAG, "method:cacheObj#clazzName=" + clazzName);
        CACHE.put(clazzName, o);
    }

    public Object getObj(Class<?> clazz) {
        String name = clazz.getName();
        Object obj = CACHE.get(name);
        Log.d(TAG, "method:getObj#obj=" + obj);
        return obj;
    }

    public Object getMsgCacheObj(Class<?> clazz) {
        String clazzName = clazz.getName();
        Log.d(TAG, "method:getMsgCacheObj#clazzName=" + clazzName);
        Object obj = CACHE.get(clazzName);
        Log.d(TAG, "method:getMsgCacheObj#CACHE#obj=" + obj);
        if (obj != null) {
            // 获取到实例后,就是要使用当前实例,所以将重置对象所有属性;
            // 同时flag=false时,当前实例也就不能同时被其它调用,只能等当前实例的工作完成,才能重用当前对象;
            if (obj instanceof BaseMsgBuider) {
                ((BaseMsgBuider) obj).recycle();
            } else if (obj instanceof MsgHelper) {
                ((MsgHelper) obj).recycle();
            }
        } else {
            try {
                obj = clazz.newInstance();
                cacheObj(obj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "method:getMsgCacheObj#newInstance#obj=" + obj);
        }
        return obj;
    }

}

 

       以上只是简单的演示,以具体的IM处理消息的业务为例,在具体的项目开发中,不同消息类型的业务处理是复杂的,不同策略类内部的业务也是复杂的,经过策略模式的业务分离,将不同类型的业务就封装到了各自的业务模块,让整体的业务流程更加清晰,即便于代码的阅读,也便于后期的业务开发扩展和维护。

GitHub地址

由于作者水平有限,语言描述及代码实现中难免有纰漏,望各位看官多提宝贵意见!

Hello , World !

感谢所有!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

windfallsheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值