迪米特法则在Android实际开发中的运用

迪米特法则(Law of Demeter,LoD)也称为最少知识原则(Least Knowledge Principle,LKP)。如果两个类不必彼此间直接通信,那么这两个类不应该发生直接的相互关系。如果其中一个类需要调用另一个类的方法,可以通过第三者转发这个调用。
迪米特法则还有一个英文解释:Only talk to your immedate friends(只与直接的朋友通信)。对于这个翻译,我觉得是很贴切很合理的,引用《Java与模式》中的事例来说,张三和李四是朋友,李四和王五是朋友,张三和王五互不认识,如果张三想调用王五的方法,在迪米特法则的前提下,应该是张三通过李四去调用王五的方法,这就是为什么翻译为只与直接的朋友通信。
一句话总结上述两个解释:只与朋友通信,不要搭理陌生人。

先不说那么多了,直接用Android实际开发中的应用来实现来逐步说明这个法则,MVP是当今开发中一个比较流行的模式,本篇通过MVP模式加上adapter来说明,先上一张图片然后撸代码,图片如下:
这里写图片描述

这个布局方式有N种方式,根据个人喜好,这个界面之前是别人帮我写的,采用relativeLayout布局,toolbar+recyclerview+button,当时做到这个页面的时候,想到有三套解决方案,如下:
1、实例化adapter的时候,把presenter传过来
2、实例化的时候把activity传过来
3、通过接口,让adapter通过调用activity,在activity中调用presenter

乍一看,可能觉得第三种最烦,前两种方案,只需要在adapter中直接调用就可以,但是就把adapter与activity或者presenter关联到一起了,把activity传过来,这完全是一个很脑残的想法,adapter是activity中的一部分,再把activity传过来,这就形成了一个强耦合。presenter和adapter是完全不相关的两个类,如果把presenter传过来,两个完全没关系的类关联到一起,这样真的好吗?类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
当我们刚学软件开发的时候,书本上就提示“高内聚低耦合”,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。

EvaluationListActivity.java

/**
 * 
 * created by zero on 2016-6-27
 * 
 * 评价列表
 * 
 */
public class EvaluationListActivity extends
        BaseActivity<EvaluationListPresenter> implements IEvaluation
{

    @ViewInject(R.id.rv_goods_reviews)
    private RecyclerView rv_goods_reviews;
    @ViewInject(R.id.btn_submit)
    private Button btn_submit;

    private EvaluationListAdapter adapter;

    @Override
    protected int initLayout() {
        // TODO Auto-generated method stub
        return R.layout.activity_goods_reviews;
    }

    @Override
    protected void initViewAndListen() {
        // 调用父类,初始化toolbar,在此不暴露父类,(*^__^*) 嘻嘻……
        super.initToolbar();
        // 调用父类,初始化LinearLayoutManager
        rv_goods_reviews.setLayoutManager(super
                .initLayoutManager(LinearLayoutManager.VERTICAL));
        btn_submit.setOnClickListener(this);
    }

    @Override
    protected void initData() {
        // TODO Auto-generated method stub
        presenter.initData();
    }

    @Override
    protected void onclick(View v) {
        // TODO Auto-generated method stub
        switch (v.getId())
        {
        case R.id.btn_submit:
            submit();
            break;

        default:
            break;
        }
    }

    // 通过回调函数,抓取map
    private void submit() {
        // TODO Auto-generated method stub
        adapter.getMap(new IEvaluationMap()
        {

            @Override
            public void sendEvaluationData(Map<String, EditText> map) {
                // TODO Auto-generated method stub
                List<EvaluationListToJsonModel> list = new ArrayList<EvaluationListToJsonModel>();
                for (Map.Entry<String, EditText> mEntry : map.entrySet())
                {
                    EvaluationListToJsonModel model = new EvaluationListToJsonModel();
                    model.goods_id = mEntry.getKey();
                    model.comment = mEntry.getValue().getText().toString();
                    list.add(model);
                }
                /**
                 * 服务器那边需要传送base64,base64基于mime协议,每76字符便会回车,所以此处需要去除回车,
                 * 关于base64有疑问,请看相关资料
                 */
                String comment = Base64.encodeToString(
                        GsonHelper.toJson(list).getBytes(), Base64.DEFAULT).replace("\n", "");
                if (!TextUtils.isEmpty(comment))
                {
                    presenter.submit(comment);
                } else
                {
                    toast("error");
                }
            }
        });
    }

    @Override
    protected Class<EvaluationListPresenter> getPsClass() {
        // TODO Auto-generated method stub
        return EvaluationListPresenter.class;
    }

    @Override
    protected Object getIView() {
        // TODO Auto-generated method stub
        return this;
    }

    @Override
    public void sendData(OrderMainModel mModel) {
        adapter = new EvaluationListAdapter(EvaluationListActivity.this,
                mModel.goods_list);
        rv_goods_reviews.setAdapter(adapter);
    }
}

EvaluationListAdapter.java

/**
 * 
 * created by zero on 2016-6-27
 * 
 * 评价列表的adapter
 * 
 */
public class EvaluationListAdapter extends RecyclerView.Adapter<ViewHolder>
{

    private Context context;
    private List<OrderGoodsModel> list ;
    private Map<String, EditText> map = new LinkedHashMap<String, EditText>();

    public EvaluationListAdapter(Context context, List<OrderGoodsModel> list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public int getItemCount() {
        // TODO Auto-generated method stub
        return list==null?0:list.size()+1;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int posiotn) {
        // TODO Auto-generated method stub
        if(holder instanceof ItemViewHolder){
            ImageUtil.display(context, list.get(posiotn).goods_thumb, ((ItemViewHolder) holder).iv_gift_img);
            ((ItemViewHolder) holder).tv_gift_price.setText("¥"+list.get(posiotn).goods_price);
            ((ItemViewHolder) holder).tv_gift_number.setText("x"+list.get(posiotn).goods_number);
            if(list.get(posiotn).is_gift.equals("1")){
                ((ItemViewHolder) holder).tv_gift_tile.setText(list.get(posiotn).goods_name);
            }else{
                ((ItemViewHolder) holder).tv_gift_tile.setText(list.get(posiotn).goods_name);
            }
            map.put(list.get(posiotn).goods_id, ((ItemViewHolder) holder).et_content);
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // TODO Auto-generated method stub
            View view = LayoutInflater.from(context).inflate(
                    R.layout.item_goods_reviews,null);
            return new ItemViewHolder(view);
    }

    class ItemViewHolder extends RecyclerView.ViewHolder
    {

        public ItemViewHolder(View itemView)
        {
            super(itemView);
            // TODO Auto-generated constructor stub
            ViewUtils.inject(this, itemView);
        }

        @ViewInject(R.id.iv_gift_img)
        private ImageView iv_gift_img;
        @ViewInject(R.id.tv_gift_tile)
        private TextView tv_gift_tile;
        @ViewInject(R.id.tv_gift_price)
        private TextView tv_gift_price;
        @ViewInject(R.id.tv_gift_number)
        private TextView tv_gift_number;
        @ViewInject(R.id.et_content)
        private EditText et_content;
    }

    //供activity回调
    public void getMap(IEvaluationMap iMap){
        iMap.sendEvaluationData(map);
    }
}

EvaluationListPresenter.java

public class EvaluationListPresenter extends BasePresenter
{
    private String order_id;
    private Context context;
    private Handler handler;
    private IEvaluation iView;
    private static final int MEMBER_ORDER_CODE = 0x000002;
    private static final int GOODS_COMMENTS_CODE = 0x000003;

    @Override
    public void initBaseData(Context context, Handler handler, Object iView,
            Intent intent) {
        this.context = context;
        this.handler = handler;
        if(iView instanceof IEvaluation){
            this.iView = (IEvaluation) iView;
        }
        order_id = intent.getStringExtra("order_id");
    }

    @Override
    public void initData() {
        // TODO Auto-generated method stub
        params.put("act", getActionName());
        params.put("st", "detail");
        params.put("order_id", order_id);
        params.put("token", Constants.getInstance().token);
        params.setSuccessMsgWhat(MEMBER_ORDER_CODE);
        HttpTools.request(params, context, handler);
    }

    public void submit(String comment){
        params = new RequestParams();
        params.put("act", URLUtils.GOODS_COMMENTS);
        params.put("st", "add");
        params.put("order_id", order_id);
        params.put("comment", comment);
        params.put("token", Constants.getInstance().token);
        params.setSuccessMsgWhat(GOODS_COMMENTS_CODE);
        HttpTools.request(params, context, handler);
    }

    @Override
    public String getActionName() {
        // TODO Auto-generated method stub
        return URLUtils.MEMBER_ORDER;
    }

    @Override
    public void handMsg(Message msg) {
        // TODO Auto-generated method stub
        switch (msg.what)
        {
        case MEMBER_ORDER_CODE:
            iView.sendData(JsonToModel.getJsonToModel(msg, OrderMainModel.class));
            break;

        case GOODS_COMMENTS_CODE:
            //成功后的处理,此处省略
            break;

        default:
            break;
        }
    }
}

OrderMainModel.java

public class OrderMainModel
{
    public OrderInfoModel order_info;
    public OrderMemberModel member_info;
    public List<OrderPayModel> pay_info ;
    public OrderShipModel ship_info;
    public List<OrderGoodsModel> goods_list ;
}

IEvaluation.java

public interface IEvaluation
{
    void sendData(OrderMainModel mModel);
}

EvaluationListToJsonModel.java

public class EvaluationListToJsonModel
{
    public String goods_id;
    public String comment;
}

以上是本次的实现代码,在adapter里面调用presenter,如果在adapter里面直接使用presenter,那么在初始化adapter的时候,就要从activity中传一个presenter到adapter,adapter中便可以直接调用presenter,这样可以实现我们需要的功能,但是这样做就使presenter和adapter两个原本不相关的两个类重新关联到一起,为了进一步解耦,通常我们使用activity实现一个为adapter量身打造的接口,为什么是量身打造?因为接口也是提倡单一职责原则,在初始化adapter的时候,把接口传过去,在adapter中通过调用接口来调用activity,在activity中再去调用presenter,这样,adapter可以与presenter交互的同时,两者也是尽可能少的知道对方。

好处:

  1. 解耦,不通过具体的类与类去实现,而是通过接口实现。
  2. 严格遵循MVP模式,adapter属于activity的一部分,主要职责是展示view,对于业务逻辑的处理,当时是放在P层。

本篇纯属个人见解,如有错误,欢迎批评指正。

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值