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

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. 实现快速迭代的引擎设计 - Capcom RE Engine的架构与实现

    [译]实现快速迭代的引擎设计 - Capcom RE Engine的架构与实现 ken hu· 6 天前 原文(日文):ラピッドイテレーションを実現するゲームエンジンの設計 CEDEC2016上的一个 ...

  2. 多线程调用WebClient速度变慢的问题

    设置 System.Net.ServicePoint 对象所允许的最大并发连接数 System.Net.ServicePoint 对象允许的最大并发连接数.默认值为 2 System.Net.Serv ...

  3. POJ 2083 Fractal

    Fractal Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 6646   Accepted: 3297 Descripti ...

  4. BATCH(BAT批处理命令语法)

    bat语法备忘扩展名是bat(在nt/2000/xp/2003下也可以是cmd)的文件就是批处理文件[@more@] bat语法备忘扩展名是bat(在nt/2000/xp/2003下也可以是cmd)的 ...

  5. 在没安装OFFICE的服务器SSIS中进行EXCEL的ETL操作!

    由于OFFICE 2010的安装包比较庞大,如果仅仅为了在服务器中实现操作EXCEL,完全没有必要安装整个OFFICE,是否可以不装OFFICE也实现与OFFICE文件的互相操作呢?答案是肯定的,在S ...

  6. SmartDoc(YUIDoc) 注释编写

    上面介绍了JS文档和Demo生成工具SmartDoc,本篇开始介绍一下注释的编写.SmartDoc使用的是YUIDoc的引擎,所以的注释规则都一样,先简单介绍下YUIDoc的注释编写. 编写注释是一个 ...

  7. Java Job

    1.在META-INF\MANIFEST.MF中指定Main-Class Main-Class: test.HelloWorld 命令:java -jar fileName.jar 2.不指定Main ...

  8. java正则表达式小练习(IP地址检测、排序,叠词的处理,邮件地址的获取)

    import java.util.Arrays; import java.util.Comparator; import java.util.Scanner; import java.util.reg ...

  9. 爬虫技术 -- 基础学习(四)HtmlParser基本认识

    利用爬虫技术获取网页源代码后,针对网页抽取出它的特定文本内容,利用正则表达式和抽取工具,能够更好地抽取这些内容. 下面介绍一种抽取工具 -- HtmlParser HtmlParser是一个用来解析H ...

  10. bootstrap插件学习-bootstrap.collapse.js

    先看bootstrap.collapse.js的结构 var Collapse = function ( element, options ){} // 构造器 Collapse.prototype ...