以下内容是分析安卓源码所得:

1: 使用默认样式创建View的方式, 源码文件 Button.Java 

注:此文参考http://www.linzenews.com/ 中的内容所写,如侵删!

2: 需要声明默认样式的属性, 源码文件 attrs.xml 

3:创建默认样式, 源码文件 styles.xml 

4:在APP主题中,引用默认样式 themes.xml (注意这步不能忘记) 

源码分析结束.


以下是我个人的使用经验:

1:主题中引用 radioButton样式 

2:声明默认样式属性 

3:创建默认样式 

4:使用默认样式创建View 

这篇博客我们来介绍一下策略模式(Strategy Pattern,或者叫 Policy Pattern),也是行为型模式之一。通常在软件开发中,我们为了一个功能可能会设计多种算法和策略,然后根据实际使用情况动态选择对应的算法和策略,比如排序算法中的快速排序,冒泡排序等等,根据时间和空间的综合考虑进行运行时选择。 
  针对这种情况,一个常规的方法是将多种算法写在一个类中,每一个方法对应一个具体的排序算法,或者写在一个方法中,通过 if…else 或者 switch…case 条件来选择具体的排序算法。这两种方法我们都成为硬编码,虽然很简单,但是随着算法数量的增加,这个类就会变得越来越臃肿,维护的成本就会变高,修改一处容易导致其他地方的错误,增加一种算法就需要修改封装算法类的源代码,即违背了开闭原则和单一职责原则。 
  如果将这些算法或者策略抽象出来,提供一个统一的接口,不同的算法或者策略有不同的实现类,这样在程序客户端就可以通过注入不同的实现对象来实现算法或者策略的动态替换,这种模式的可扩展性、可维护性也就更高,这就是下面讲到的策略模式。 
 

设计模式总目录

  java/android 设计模式学习笔记目录

特点

  策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。 
  策略模式的使用场景:

  • 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时;
  • 需要安全地封装多种同一类型的操作时;
  • 出现同一抽象类有多个子类,而又需要使用 if-else 或者 switch-case 来选择具体子类时。

UML类图

  我们来看看策略模式的 uml 类图: 
   
策略模式有三个角色:

  • Context:用来操作策略的上下文环境;
  • Stragety:策略的抽象;
  • ConcreteStrategy:具体的策略实现。

  据此我们可以写出策略模式的通用代码: 
Stragety.class

public interface Stragety {
    void algorithm();
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

ConcreteStragetyA.class 和 ConcreteStragetyB.class

public class ConcreteStragetyA implements Stragety{
    @Override
    public void algorithm() {
        System.out.print("ConcreteStragetyA\n");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
public class ConcreteStragetyB implements Stragety{
    @Override
    public void algorithm() {
        System.out.print("ConcreteStragetyB\n");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

默认策略类ConcreteStragetyDefault.class

public class ConcreteStragetyDefault implements Stragety{
    @Override
    public void algorithm() {
        System.out.print("null stragety");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Context.class 和测试代码

public class Context {

    private Stragety stragety;

    public Context() {
        stragety = new ConcreteStragetyDefault();
    }

    public void algorithm() {
        stragety.algorithm();
    }

    public void setStragety(Stragety stragety) {
        if (stragety == null) {
            throw new IllegalArgumentException("argument must not be null!!!");
        }
        this.stragety = stragety;
    }

    public static void main(String args[]) {
        Context context = new Context();
        context.setStragety(new ConcreteStragetyA());
        context.algorithm();
        context.setStragety(new ConcreteStragetyB());
        context.algorithm();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

代码很简单,一目了然,没有if-else,没有 switch-case。核心就是建立抽象,将不同的策略构建成一个个具体的策略实现,通过不同的策略实现算法替换,在简化逻辑、结构的同时,增强系统的可读性、稳定性和可扩展性,这对于较为复杂的业务逻辑显得更为直观,扩展也更加方便。

示例与源码

Android 源码中策略模式

  其实在 Android 源码中策略模式使用的次数也是很多,大家常见的动画中就有使用到策略模式:

public abstract class Animation implements Cloneable {
    /**
     * The interpolator used by the animation to smooth the movement.
     */
    Interpolator mInterpolator;
    ....
    /**
     * Sets the acceleration curve for this animation. Defaults to a linear
     * interpolation.
     *
     * @param i The interpolator which defines the acceleration curve
     * @attr ref android.R.styleable#Animation_interpolator
     */
    public void setInterpolator(Interpolator i) {
        mInterpolator = i;
    }
    ....
    /**
     * Gets the transformation to apply at a specified point in time. Implementations of this
     * method should always replace the specified Transformation or document they are doing
     * otherwise.
     *
     * @param currentTime Where we are in the animation. This is wall clock time.
     * @param outTransformation A transformation object that is provided by the
     *        caller and will be filled in by the animation.
     * @return True if the animation is still running
     */
    public boolean getTransformation(long currentTime, Transformation outTransformation) {
        ......

            final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
            applyTransformation(interpolatedTime, outTransformation);
        ......
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

Animation 类就是很典型用到策略模式的类,它里面会有一个 Interpolator 插值器对象,用来在执行动画的时候达到所需要的速度变化效果,系统提供的插值器有 LinearInterpolator(线性插值器,动画的执行速度相等),AccelerateDecelerateInterpolator (加速减速插值器,动画的执行起始加速,结尾减速),DecelerateInterpolator(减速插值器,速度随着动画的执行变慢),以及回弹插值器等等,感兴趣的上网查阅一下相关资料即可(我曾经在android下拉刷新框架用过插值器的相关类,是一个很有用的类)。

wiki example

  这里我就仍然以 wiki 上的代码为例,商场在不同时段会有打折促销活动,顾客在不同的时段分别进行购买,最后得出一个价格: 
BillingStragety.class

interface BillingStrategy {
    public double getActPrice(double rawPrice);
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

NormalStrategy.class 和 HappyHourStragety.class

// Normal billing strategy (unchanged price)
class NormalStrategy implements BillingStrategy {
    @Override
    public double getActPrice(double rawPrice) {
        return rawPrice;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
// Strategy for Happy hour (50% discount)
class HappyHourStrategy implements BillingStrategy {
    @Override
    public double getActPrice(double rawPrice) {
        return rawPrice * 0.5;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Customer.class

class Customer {

    private List<Double> drinks;
    private BillingStrategy strategy;

    public Customer(BillingStrategy strategy) {
        this.drinks = new ArrayList<Double>();
        this.strategy = strategy;
    }

    public void add(double price, int quantity) {
        drinks.add(strategy.getActPrice(price * quantity));
    }

    // Payment of bill
    public void printBill() {
        double sum = 0;
        for (Double i : drinks) {
            sum += i;
        }
        System.out.println("Total due: " + sum);
        drinks.clear();
    }

    // Set Strategy
    public void setStrategy(BillingStrategy strategy) {
        this.strategy = strategy;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

main

public class StrategyPatternWiki {

    public static void main(String[] args) {
        Customer firstCustomer = new Customer(new NormalStrategy());

        // Normal billing
        firstCustomer.add(1.0, 1);

        // Start Happy Hour
        firstCustomer.setStrategy(new HappyHourStrategy());
        firstCustomer.add(1.0, 2);

        // New Customer
        Customer secondCustomer = new Customer(new HappyHourStrategy());
        secondCustomer.add(0.8, 1);
        // The Customer pays
        firstCustomer.printBill();

        // End Happy Hour
        secondCustomer.setStrategy(new NormalStrategy());
        secondCustomer.add(1.3, 2);
        secondCustomer.add(2.5, 1);
        secondCustomer.printBill();

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

不同时段买的东西,最后得出一个价钱,多种算法动态切换,用户不用去关心具体的内部细节。

总结

  策略模式主要是用来分离算法,在相同的行为抽象下有不同的具体实现策略。这个模式很好的演示了开闭原则:定义抽象,增加新的策略只需要增加新的类,然后在运行中动态更换即可,没有影响到原来的逻辑,从而达到了很好的可扩展性。 
  优点:

  • 结构清晰明了、使用简单直观;
  • 耦合度相对而言较低,扩展方便;
  • 操作封装也更为彻底,数据更为安全。

  缺点也很明显,这当然也是很多设计模式的通病:类的增多,随着策略的增加,子类也会变得繁多。

Android使用默认样式创建View的几个姿势的更多相关文章

  1. Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

    零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第 ...

  2. Android spinner默认样式不支持换行和修改字体样式的解决方法

    在spinner中显示的数据过多,需要换行,而Android自身提供的android.R.layout.simple_spinner_dropdown_item样式不支持换行,因此参考android提 ...

  3. Android通过xml生成创建View的过程解析

    Android的布局方式有两种,一种是通过xml布局,一种是通过java代码布局,两种布局方式各有各的好处,当然也可以相互混合使用.很多人都习惯用xml布局,那xml布局是如何转换成view的呢?本文 ...

  4. Android开发必知--使用View.setId的正确姿势

    这两天在写一个柱状图的自定义控件,用的直接继承ViewGroup的方式实现的,我们都知道,这是自定义控件里面最简单的一种了,有时间写个总结分享一下.这里我想说的重点是,在写这个自定义控件的时候遇到了个 ...

  5. Android中Context样式分析

    目录 1.样式定义以及使用 1.1.默认样式 1.2.样式定义及使用 1.3.当前样式下attr属性的获取 1.4.属性集合的定义与获取 2.Activity中Theme的初始化流程 2.1.系统调用 ...

  6. 【Android Training UI】创建自定义Views(Lesson 1 - 创建一个View类)

    发布在我的网站 http://kesenhoo.github.io/blog/2013/06/30/android-training-ui-creating-custom-views-lesson-1 ...

  7. Android UI 统一修改Button控件的样式,以及其它系统控件的默认样式

    先介绍下修改原理:首先打开位于android.widget包下面的Button.java文件,这里有一句关键的代码如下: public Button(Context context, Attribut ...

  8. ionic默认样式android和ios的一些不同(当时真是纠结啊~)

    当时测试的时候看到android和ios上有那么大差别,特别崩溃啊... 还好看到了这篇文章,文章原文是Ionicchina中文网上的:http://ionichina.com/topic/54e45 ...

  9. ionic默认样式android和ios差异

    ionicframework中android和ios在默认样式上有一些不同的地方,官方文档中都有说明,但是经常会想不起. 一.差异: 1.tab位置,$ionicConfigProvider, tab ...

随机推荐

  1. 关于bootstrapValidator提交问题的解决

    关于bootstrapValidator的AJAX提交有几种方法: 1.form中一定要放一个类型为submit的按钮,然后添加 success.form.bv 事件,如下 on('success.f ...

  2. CreateProcessAsUser,C#写的windows服务弹框提示消息或者启动子进程

    服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分.我们可以把服务想像成一种特殊的应用程序,它随系统的“开启-关闭”而“开始-停止”其工作内容,在这期间无需任何 ...

  3. JDK的下载、安装及环境变量的配置

    官网下载JDK: www.oracle.com 或者 www.java.sun.com   安装JDK: 双击运行下载的 jdk-8u25-windows-i586.exe即可. 假设安装目录为:D: ...

  4. CSS之边框覆盖

    今天想做一个淘宝导航来练练手,遇到了边框覆盖的问题.如下图: li的红色边框盖不住该灰色边框.后来问经验人士告诉我,这种边框覆盖是会出现无法100%保证正常的情况,遂得到如下3中解决方案: 1.以后遇 ...

  5. oracle 11g 如何创建、修改、删除list-list组合分区

    Oracle11g在分区方面做了很大的提高,不但新增了4种复合分区类型,还增加了虚拟列分区.系统分区.INTERVAL分区等功能. 9i开始,Oracle就包括了2种复合分区,RANGE-HASH和R ...

  6. mysql安装出现error Nr.1045 (转)

    http://www.cnblogs.com/Ivan-j2ee/archive/2012/09/22/2698278.html 我们在windows下安装mysql时会出现Access denied ...

  7. Sass学习之路:注释、变量以及导入

    前言 由于.sass不兼容CSS代码,所以以下内容完全使用.scss的语法. Sass注释 Sass中除了提供CSS中的标准注释之外,还提供了一种静默注释: /* 我是标准注释 */ // 我是静默注 ...

  8. 《微信小程序七日谈》- 第四天:页面路径最多五层?导航可以这么玩

    <微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩 微信小 ...

  9. SecureCRT连接linux设置vim显示颜色

    只需要两个步骤: 1) 选项 --> 会话选项 --> 终端 --> 仿真 -->  勾选“ANSI 颜色”. 2)  在.bashrc中添加:export TERM=xter ...

  10. 2015 Multi-University Training Contest 1 - 1001 OO’s Sequence

    OO’s Sequence Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5288 Mean: 给定一个数列,让你求所有区间上满足 ...