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

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. cocos在win平台exe无法使用 UserDefault 解决方法

    exe模拟器用来调度cocos本来是很方便的事情,但最近很多win10策划无法调用UserDefault.一直以为是权限问题,今天有空读一下码才发现.原来是cocos的bug.存在本地的UserDef ...

  2. 译:C#面向对象的基本概念 (Basic C# OOP Concept) 第二部分(封装,抽象,继承)

    6.封装 封装就是对外部类隐藏成员或变量.我已经说过房子的保安仅仅被限制在房子的入口处,不需要知道屋内发生了什么.房主对保安隐藏了屋内所发生的任何事,以便更安全.隐藏和限制就被称为封装. 例如我们有两 ...

  3. notepad++批量头尾追加

    每行首添加 在“查找目标”里输入上尖号“^”,上尖号代表每行的开头 每行尾追加

  4. 微信公众号开发第二课 百度BAE搭建和数据库使用

    上一节主要是一些准备知识,本课还是准备知识,开发微信也可以不使用数据库,但是要想搭建一些查询类应用,就可能使用到数据库操作,所以本节主要涉及到百度BAE上面的数据库表的创建,插入数据,修改数据,删除数 ...

  5. Character Controller (角色控制器) 中 Move()和SimpleMove() 的区别

    首先给出两者的圣典: CollisionFlagsMove(Vector3motion); Description A more complex move function taking absolu ...

  6. Device eth0 does not seem to be present, delaying initialization.转载

    昨天在vm里面克隆了个虚拟机,克隆之后,启动了网卡起不来,已启动就报 Device eth0 does not seem to be present, delaying initialization. ...

  7. 移除了css框架,世界干净了

    在之前的webapp项目里,我使用了bootstrap作为三方的css库,只调取了其中一部分源码的less使用,大部分代码仍然是自己写的. 自己的代码也是参照bootstrap的目录结构和它的一些规范 ...

  8. HT全矢量化的图形组件设计

    HT一直被客户称道的就是其全矢量化的设计特色,矢量相比传统图片好处太多了: 矢量可无级缩放,界面不失真不模糊 描述矢量的文本内容远比图片小得多 目前各种window.devicePixelRatio不 ...

  9. 【第三课】ANR和OOM——贪快和贪多的后果(下)

    Out of Mana,法力耗尽. 内存就像法力,耗尽了就什么都不能做了.有时候一个应用程序占用了太大的内存,超过了Android系统为你规定的限制,那么系统就会干掉你,以保证其他app有足够的内存. ...

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

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