Android进阶之路Android开发经验谈

android 源码设计模式读书笔记(一)

2019-06-29  本文已影响2人  刘景昌

这是第二次读这本书了 有时感觉讲的事真的不错
第一次读完什么都没有留下 除了已经不知道哪去的源码 只剩下诗和远方
主要是长时间不看你 改忘得都差不多了 现在有时间在读一遍 希望 可以把这本书的读书笔记一直写下去
大概一中午时间读完了 第一章 最大的感慨就是小民最开始真的是碰到一个非常优秀又严格的主管 这真是一件让人羡慕 有难以达成的事 作为一个小场的程序员 我们只能在自己的摸索中前进了 闲话与羡慕的话不多少了 第一章的读书笔记
为他单开一张 真的是感觉他才是本书最重要的章节
学习设计模式首先要学习的是 六大原则
设计的六大原则:
(一)单一职责原则:就一个类而言应该仅有一个引起他变化的原因
(二)开闭原则:软件中的类应该是对扩展开放的,对修改是封闭的。
(三)里氏置换原则:引用基类的地方必须能够透明的使用的的子类对象(感觉还没写过不能的)
优点:(1) 代码重用,减少创建类的成本,每个子类都拥有父类的实现方法
(2)子类与父类相似,但由于父类有区别
(3)提高代码的可扩展性
缺点:(1)继承是侵入性的只要继承,就必须拥有父类所有的方法和属性
(2)可能造成代码冗余,灵活性降低。
(四)依赖倒置原则:高层次的模块不依赖于低层次的模块的实现细节
它有这么几个关键点:
(1)高层模块不能依赖低层模块,两者都应该依赖于其抽象
(2)抽象不依赖于细节
(3)细节依赖于抽象
(五)接口隔离原则:类之间的关系应该建立在最小的接口只上
(六)迪米特原则:至于具有直接关系的类进行交互。
下面是自己在实践过程中的应用和思考
我们要写的是一个自定义组合View 它包括好几种类型
类型一

image.png
类型二
image.png
类型三
image.png
类型四
image.png
类型五
image.png
类型六
image.png
第一版
分析:我们需要建一个实体类来标识每一条的属性
public class TimeOneVouchers  {
    private String time;
    private String voucherNo;
    private String storeName;
}
创建一个LinearLayout来动态添加
public class OrderStoreUserView extends LinearLayout {
    // 当前状态为所有券都被使用
    public static final int SHOW_TYPE_ALL_USE = 0x0001;
    // 当前状态为有券未都被使用--(已使用)
    public static final int SHOW_TYPE_NO_ALL_USE = 0x0010;
    // 当前状态为所有券未都已经失效
    public static final int SHOW_TYPE_NO_ALL_FAILURE = 0x0100;
    // 当前状态为有券未都被使用--(已退款)
    public static final int SHOW_TYPE_NO_ALL_USE_REFUND = 0x0101;
    private Context mContext;
    private LinearLayout ll_use;
    private TextView tv_order_store_use_num;

    private TextView tv_use_store_time;
    private TextView use_store_time;
    private TextView tv_vouchers_store;
    private TextView vouchers_store;
    private TextView vouchers_num;
    private TextView tv_vouchers_num;

    public OrderStoreUserView(Context context) {
        this(context, null);
    }

    public OrderStoreUserView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public OrderStoreUserView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        initView();
    }

    private void initView() {
        LayoutInflater.from(mContext).inflate(R.layout.layout_order_store_use, this, true);
        ll_use = findViewById(R.id.ll_use);
        tv_order_store_use_num = findViewById(R.id.tv_order_store_use_num);
    }

    /***
     *
     * @param type 当前使用券的显示状态 SHOW_TYPE_ALL_USE,SHOW_TYPE_NO_ALL_USE,SHOW_TYPE_NO_ALL_FAILURE
     * @param timeOneVouchersList
     */
    public void setViewType(int type, List<TimeOneVouchers> timeOneVouchersList) {
        for (int i = 0; i < timeOneVouchersList.size(); i++) {
            View view = LayoutInflater.from(mContext).inflate(R.layout.layout_item_store_use, null, false);
            initItemView(view);
            UserVouchers userVouchers = timeOneVouchersList.get(i);
            setCommonData(userVouchers);
            switch (type) {
                case SHOW_TYPE_ALL_USE:
                    setViewAllUse(i, timeOneVouchersList, userVouchers);
                case SHOW_TYPE_NO_ALL_USE:
                    tv_order_store_use_num.setText("已使用(" + timeOneVouchersList.size() + ")份");
                    break;
                case SHOW_TYPE_NO_ALL_FAILURE:
                    setViewGone();
                    tv_order_store_use_num.setText("已失效(" + timeOneVouchersList.size() + ")份");
                    break;
                case SHOW_TYPE_NO_ALL_USE_REFUND:
                    setViewGone();
                    tv_order_store_use_num.setText("已退款(" + timeOneVouchersList.size() + ")份");
                    break;
            }

            ll_use.addView(view);
        }
    }

    //设置公共数据
    private void setCommonData(UserVouchers userVouchers) {
        tv_vouchers_num.setText(userVouchers.getVouchersNum());
        tv_use_store_time.setText(userVouchers.getTime());
        tv_vouchers_store.setText(userVouchers.getStoreName());
    }

    //初始化View
    private void initItemView(View view) {
        use_store_time = view.findViewById(R.id.use_store_time);
        tv_use_store_time = view.findViewById(R.id.tv_use_store_time);

        tv_vouchers_store = view.findViewById(R.id.tv_vouchers_store);
        vouchers_store = view.findViewById(R.id.vouchers_store);

        vouchers_num = view.findViewById(R.id.vouchers_num);
        tv_vouchers_num = view.findViewById(R.id.tv_vouchers_num);
    }

    //只显示券码 并画中横线
    private void setViewGone() {
        tv_vouchers_num.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); //中划线
        tv_vouchers_store.setVisibility(GONE);
        vouchers_store.setVisibility(GONE);
        use_store_time.setVisibility(GONE);
        tv_use_store_time.setVisibility(GONE);
    }

    private void setViewAllUse(int i, List<TimeOneVouchers> timeOneVouchersList, UserVouchers userVouchers) {
        tv_vouchers_store.setVisibility(GONE);
        vouchers_store.setVisibility(GONE);
        tv_vouchers_num.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); //中划线
        if (i != 0) {
            if (TextUtils.equals(timeOneVouchersList.get(i - 1).getTime(), userVouchers.getTime())) {
                vouchers_num.setVisibility(INVISIBLE);
                use_store_time.setVisibility(GONE);
                tv_use_store_time.setVisibility(GONE);
            }
        }
    }
}

这个样子完全不用考虑设计模式的第一版就新鲜出炉 虽然不用考虑设计模式但是也是完全可用的
但是看完第一章 感觉和小民的第一版完工很像 只是人家是被主管哒回来了 而 我们只能自己思考。
然后在现实中我们有碰到了一个很现实的问题提 接口的开发居然的app的界面 慢 你没有办法确认接口给你类型是什么样子的 字段 是不是time,voucherNo,storeName这三个。这该怎么办呢?要是个有脾气的程序员 或者新手可能就 字段还没给了怎么写 ,然后就等接口处了在写吧 这的确个解决方法。但是不应该这样子啊,感觉有好多自定义View都可能使用的Bean他们不能重视按照所需要用的在去改源码吧;在这里我们就应该用到依赖倒置原则 作为一个实现类时不应改 依赖于另一个实现类的细节的,我们应该让他依赖于接口 然后我就这门改写
写一个接口
public interface UserVouchers {
//券的使用时间
String getTime();
// 券的使用店铺
String getStoreName();
// 券 码
String getVouchersNum();
}
然后把List<TimeOneVouchers> 改为List<UserVouchers > 这样好像就可以了
改写后的自定View类不子啊以来与原来的具体的实现Bean只依赖于 UserVouchers接口 我们只需要等接口下来不管字段是什么样子的 只需要复写这三个方法摊入相应的属性就行了。
虽然加了这面几句话就搞定了 但的确也是对面向对象的应用
这块优化后实际问题已经解决了,提交代码搞定。
虽然功能已经搞定了,但是我们来看一看还有没有其他不符合面向对象的地方继续优化
优化前我们的数据结构是这样的


image.png

根据setViewType(int type, List<UserVouchers> timeOneVouchersList)这个方法进来的参数来决定每个加载不同View的类型并赋值 明显就不符合了单一性原则
每次技师只要修改一部分的功能还要修改这个类的代码只明显是和他本身的功能无关
那我们就需要修改这个类的数据结构了
根据数据结构分析
先画了一下优化后的UML


image.png
这样谁不是更加清晰了呢
而且我问吧单个的功能分开是不就符合的 单一性与隔离性的原则
然后就可以开始优化代码 反正只要是符合6大原则 基本上都是设计模式
所以有些东西可以系统的想上面靠 有些不可以而已 比如说 自定义View的参数构造一般都会使用建造者模式等等 我们要是读完整本书 即使记不住具体的设计模式也一定要记住这个第一张的6大原则 只需要 我们在做功能的基础设计的时候网上面靠就就行了 就比如说我上上面的这种想法其实也就是一个泛指,就比如说我们在做前端 多种支付的时候也可以涉及到。
我发现这个类图画完只是一个预想 实际操作过程中 有余还有一写含有公共的方法
还有少的一些参数
最终修改类图为
image.png
1.完成接口
public interface ItemView {
  View setView(Context context, List<UserVouchers> userVouchers,int i, TextView tv_order_store_use_num);
  void  initItemView(View view);
  void setCommonData(UserVouchers userVouchers);
  void setViewType(List<UserVouchers> userVouchers, int i, TextView tv_order_store_use_num);
}
  1. 完成基类
public abstract class BaseItemView implements ItemView {

    public TextView tv_use_store_time;
    public TextView use_store_time;
    public TextView tv_vouchers_store;
    public TextView vouchers_store;
    public TextView vouchers_num;
    public TextView tv_vouchers_num;

    @Override
    public View setView(Context context, List<UserVouchers> userVouchers,int i,TextView tv_order_store_use_num) {
        View view = LayoutInflater.from(context).inflate(R.layout.layout_item_store_use, null, false);
        initItemView(view);
        setCommonData(userVouchers.get(i));
        setViewType(userVouchers,i,tv_order_store_use_num);
        return view;
    }

    @Override
    public void initItemView(View view) {


        use_store_time = view.findViewById(R.id.use_store_time);
        tv_use_store_time = view.findViewById(R.id.tv_use_store_time);

        tv_vouchers_store = view.findViewById(R.id.tv_vouchers_store);
        vouchers_store = view.findViewById(R.id.vouchers_store);

        vouchers_num = view.findViewById(R.id.vouchers_num);
        tv_vouchers_num = view.findViewById(R.id.tv_vouchers_num);
    }

    @Override
    public void setCommonData(UserVouchers userVouchers) {
        tv_vouchers_num.setText(userVouchers.getVouchersNum());
        tv_use_store_time.setText(userVouchers.getTime());
        tv_vouchers_store.setText(userVouchers.getStoreName());
    }


    //只显示券码 并画中横线
    public void setViewGone() {
        tv_vouchers_num.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); //中划线
        tv_vouchers_store.setVisibility(GONE);
        vouchers_store.setVisibility(GONE);
        use_store_time.setVisibility(GONE);
        tv_use_store_time.setVisibility(GONE);
    }


}

3.完成各个的实现类

public class AllUsersView extends BaseItemView {

    @Override
    public void setViewType(List<UserVouchers> userVouchers, int i, TextView tv_order_store_use_num) {
        tv_order_store_use_num.setText("已使用(" + userVouchers.size() + ")份");
        tv_vouchers_store.setVisibility(GONE);
        vouchers_store.setVisibility(GONE);
        tv_vouchers_num.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); //中划线
        if (i != 0) {
            if (TextUtils.equals(userVouchers.get(i - 1).getTime(), userVouchers.get(i).getTime())) {
                vouchers_num.setVisibility(INVISIBLE);
                use_store_time.setVisibility(GONE);
                tv_use_store_time.setVisibility(GONE);
            }
        }
    }
}

@Override
    public void setViewType(List<UserVouchers> userVouchers, int i, TextView tv_order_store_use_num) {
        tv_order_store_use_num.setText("已失效(" + userVouchers.size() + ")份");
        setViewGone();
    }


public class NoAllUserView extends BaseItemView {


    @Override
    public void setViewType(List<UserVouchers> userVouchers, int i, TextView tv_order_store_use_num) {
        tv_order_store_use_num.setText("已使用(" + userVouchers.size() + ")份");
    }
}



public class RefundView extends BaseItemView {


    @Override
    public void setViewType(List<UserVouchers> userVouchers, int i, TextView tv_order_store_use_num) {
        setViewGone();
        tv_order_store_use_num.setText("已退款(" + userVouchers.size() + ")份");
    }
}

4.修改调用

 for (int i = 0; i < UserVouchers.size(); i++) {
            ll_use.addView(itemView.setView(mContext, UserVouchers, i, tv_order_store_use_num));
        }

这样就改完了 这样就可以在需要改某个View是时候 具体的实体类就行了 不需要在修改OrderStoreUserView这个入口类里面的东西。

也就是第一篇会比较多了 开始学习设计模式的时候又会便的很枯燥了

上一篇下一篇

猜你喜欢

热点阅读