前言
当自己的编码时间久了之后, 会发现优秀的代码, 往往是遵循合理的设计模式进行开发的, 这些代码具备高内聚, 低耦合的特性, 能够在随时变化的需求中, 保持稳定性, 灵活性.
本文, 是在 Android 代码中去寻找「设计模式」的影子, 并不会很详细地展开各个模式的定义与应用. 开始, 盘它!
(篇幅有限且网上优秀的书籍多, 所以不要想着在这一篇文章弄清楚它们. 注: 本人水平有限, 不对的地方, 还请指出修正).
一, 单例模式
记得曾经笔试时就考过写出单例模式的实现方式: 1, 懒汉式(线程安全);2, 饿汉式(DCL);3, 静态内部类; 4, 枚举实现(最佳实现).
当某个对象的创建是比较耗时的, 如果频繁的创建与销毁的话, 对性能影响又大, 既然没有好的办法优化, 那就在内存中持有这个对象的唯一实例, 减少内存占用.
值得注意的是: 1, 单例对象创建的线程安全问题; 2,Android 中创建单例时, 如果持有 Context 容易导致内存泄露, 尽量使用 Application Context.
例如 Glide,ImageLoader 图片加载框架, 正是采用单例模式, 来获取实例对象的.
- ,Glide.with(context).load(imageUrl).into(imageView);
- ,ImageLoader.getInstance().displayImage(imageUrl,imageView);
二, Builder 模式
构建者模式把一个对象的创建与表示分离开了, 也就是说构建的过程不同, 会生产出不同的对象出来. 同时 Builder 类, 把具体产品的创建细节隐藏了, 使得我们不用关注产品具体是怎么实现的. 例如: 我们无需关注调用方法的顺序, 因为 Builder 类已经封装好了调用的顺序了. 还有这种链式调用写起来真的很爽!
最常见的就是我们 Android 里面的对话框的创建过程了, 我们通过 AlertDialog.Builder() 构建的过程中, 有没有设置按钮, 标题, 提示等, 其实创建出来的对话框风格是不一样的.
- 1,new AlertDialog.Builder()
- .setTitle("title")
- .setMessage("message")
- .setPositiveButton("ok", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- // do something
- }
- }).create();
- 2,new StringBuilder().append("A").append("B").append("C").toString();
这里介绍一个 Android Studio 的插件 -- Builder Generator, 这个插件可以省去手写 Builder 的烦恼.
三, 工厂模式
有以下几种:
简单工厂: 含静态方法, 也叫静态工厂, 多用 if...else 来做分支, 去创建各个实例, 方法内部如果创建的对象多的, 会略显臃肿
工厂模式: 含抽象工厂, 具体工厂, 抽象产品, 具体产品之分, 符合 "开闭原则"
抽象工厂模式: 与工厂模式的区别, 工厂模式创建单一产品, 抽象工厂能创建多种产品, 符合 "开闭原则"
工厂类封装好类的实例化过程, 隐藏了对象实例化的具体参数, 只需传入要创建类的唯一标识, 工厂类就能创建出指定的类. 换句话说: 我只告诉工厂我要什么, 工厂只负责生产, 我负责使用, 具体工厂怎么生产, 我就不管啦~
- public class ConcreteFactory extends Factory {
- public <T extends Product> T createProduct(Class<T> c){
- Product product=null;
- try {
- product = (Product)Class.forName(c.getName()).newInstance();
- } catch (Exception e) {
- // 异常处理
- }
- return (T)product;
- }
- }
如 Retrofit 可添加 Gson 转换(这里体现了 Builder 模式 和工厂模式)
- Retrofit retrofit = new Retrofit.Builder()
- .baseUrl(API_URL)
- .addConverterFactory(GsonConverterFactory.create())
- .build();
四, 策略模式
将算法单独封装起来, 使之替换时, 互不影响.
之前看过一篇文章说怎么消除项目代码中的 if...else , 运用策略模式, 将每个 if...else 里面的方法各自封装, 来解决因为大量的 if...else 导致的类臃肿.
例如: Android 中的设置动画的插值器, 替换不同插值器, 各不影响, 而且效果不同
- Animation animation = new AlphaAnimation(1,0);
- animation.setInterpolator(new AccelerateDecelerateInterpolator());
- imageView.setAnimation(animation);
- animation.start();
五, 模版模式
在抽象类中, 定义模版 (抽象) 方法, 并在子类做具体的实现. 其实就是我们经常用的 BaseActivity ,BaseFragment 那套东西, show code~
在 BaseActivity 里面保证模版方法, 按照顺序执行, 同时子类必须实现父类定义的抽象方法, 提高了复用性以及扩展性.
- public abstract class BaseActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // 1, 获取布局 id
- setContentView(getLayoutId());
- // 2, 初始化 view
- initView();
- // 3, 初始化数据
- initData();
- }
- public abstract int getLayoutId();
- public abstract void initView();
- public abstract void initData();
- }
五, 适配器模式
适配器模式, 可以解决接口不兼容的问题, 使得本不兼容的接口一起工作.
举例: 港版 iPhone 的充电器是三孔插头, 可是现在房间只有二孔插头, 所以我得网上买个三孔转二孔的转换器(相当于适配器), 这样我的三孔充电器就能在二孔插座使用了.
我们常用 ListView 使用的 Adapter , 用的就是适配器模式, Google 开发工程师, 设计代码的时候, 考虑到 ListView 每个 ItemView 有不同 UI. 为了应对这种可变性, BaseAdapter 提供 getView() 方法, 以保证最后输出的统一为 View.
- public class MyAdapter extends BaseAdapter {
- @Override
- public int getCount() {
- return 0;
- }
- @Override
- public Object getItem(int position) {
- return null;
- }
- @Override
- public long getItemId(int position) {
- return 0;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- return null;
- }
- }
六, 观察者模式
观察者模式, 多以一对多的形式依赖存在. 多个观察者同时监听着被监听的对象时, 当被监听的对象发生状态变化时候, 会通知所有观察者更新.
如: 邮件的订阅功能, 订阅某个模块, 当这个模块有新的内容更新, 会给所有订阅者发送邮件.
Android 中, 观察者模式使用的是比较频繁的, 例如: EventBus,RxJava 等. 最熟悉的就是 Adapter 的 notifyDataSetChanged() 方法了, 大家可以点进去看源码, 当数据发生改变的时候, 通知 itemView 重新布局.
- /**
- * 观察者集合
- */
- private final DataSetObservable mDataSetObservable = new DataSetObservable();
- // 此处, 省略很多代码...
- /**
- * Notifies the attached observers that the underlying data has been changed
- * and any View reflecting the data set should refresh itself.
- */
- public void notifyDataSetChanged() {
- mDataSetObservable.notifyChanged();
- }
来源: https://juejin.im/post/5c7c86526fb9a049ea39ab30