Android常用设计模式(二)

继上一篇 Android常用设计模式(一)里认识了观察者,适配器,代理等三种模式,这一篇将会讲解以下三种模式:

  • 工厂模式
  • 单例模式
  • 命令模式

1.工厂模式(Factory Pattern)

工厂模式分为简单工厂模式,工厂方法模式以及抽象工厂模式

  • 简单工厂模式:一般情况下,提供一个方法,方法的参数是一个标志位,根据标志位来创建不同的对象,这样调用的时候只需要提供一个标志位就可以创建一个实现了接口的类。
  • 工厂方法模式:将简单工厂模式的那个方法分开,不再是在工厂方法中根据标志位创建对象了。而是定义一个工厂接口,然后想创建几个不同类型的对象(即实现了同一接口的不同java类),就创建了几个不同类型的工厂。也就是创建的对象和创建对象的工厂是一一对应的。然后客户端调用的时候直接去实例化一个具体的对象工厂,创建相对应的对象。
  • 抽象工厂模式:其实这个名起的有点不知所云没有表达出这个模式的特点。其实这个模式就是工厂方法模式的稍微扩展一下而已。工厂方法模式里面,一般一个工厂接口只有一个方法,比如createMouse()。然后用实现了这个接口的具体工厂类只能生产鼠标。而抽象工厂模式就是一个工厂接口有多个方法,比如createMouse() , createKeyboard() 。 这样实现了这个工厂接口的具体工厂类就可以既生产鼠标又生产键盘。

常见实例:比如android的bitmap中常用的BitmapFactory类,创建Bitmap对象,通常使用静态工厂方法

这里主要介绍简单工厂与工厂方法的区别:

就以大话模式中小菜跟大鸟举得雷锋故事作为题材吧。

LeiFeng类:

//雷锋
public interface LeiFeng {
    void sweep();//扫地
    void wash();//洗衣
    void buyrice();//做饭
} 

Student类:

//学做雷锋的大学生
public class Student implements LeiFeng{  

    public void buyrice() {
        System.out.println("大学生做饭");
    }  

    public void sweep() {
        // TODO Auto-generated method stub
        System.out.println("大学生扫地");
    }  

    public void wash() {
        // TODO Auto-generated method stub
        System.out.println("大学生洗衣");
    }  

} 

Valuator类志愿者:

//学做雷锋的志愿者
public class Valuator implements LeiFeng{  

    public void buyrice() {
        System.out.println("志愿者做饭");
    }  

    public void sweep() {
        // TODO Auto-generated method stub
        System.out.println("志愿者扫地");
    }  

    public void wash() {
        // TODO Auto-generated method stub
        System.out.println("志愿者洗衣");
    }  

}

然后简单工厂是这么实现的:

//使用简单工厂
public class SimpleFactory {  

    public static LeiFeng createLeiFeng(String type){
        if("大学生".equals(type)){
            return new Student();
        }else if("志愿者".equals(type)){
            return new Valuator();
        }
        return null;
    }
} 

而工厂方法模式中,则多了一个接口去创建不同类型的对象:

Factory类:

//工厂方法模式,工厂接口
public interface Factory {
    LeiFeng createLeiFengFactory();
}

StudentFactory学生工厂:

//学生工厂
public class StudentFactory implements Factory{
    public LeiFeng createLeiFengFactory() {
        return new Student();
    }
} 

ValuatorFactory志愿者工厂:

//志愿者工厂
public class ValuatorFactory implements Factory{
    public LeiFeng createLeiFengFactory() {
        return new Valuator();
    }
} 

当我们实现起来时:

public static void main(String[] args) {  

    //简单工厂模式
    LeiFeng f11=SimpleFactory.createLeiFeng("大学生");
    f11.buyrice();
    LeiFeng f22=SimpleFactory.createLeiFeng("大学生");
    f22.wash();  

    //使用工厂方法模式
    Factory fac=new StudentFactory();
    LeiFeng f4=fac.createLeiFengFactory();
    f4.buyrice();
    LeiFeng f5=fac.createLeiFengFactory();
    f5.wash();
}

这里就要说说为什么要使用工厂方法模式,因为简单工厂使用起来明显要方便简约的多。从理论的角度来说,工厂方法模式更符合封闭-开放原则。即对修改封闭对扩展开放。试想后期维护过程中要增加一个种类的对象,也就是增加对接口的一种实现,简单工厂模式就要在switch…case中增加一个case项,无疑是修改了工厂方法。如果是jar包模式的,就要重新发包了。但是工厂方法模式,完全不需要更改工厂接口,只是新增加一个实现的工厂类即可(如果是jar包模式的,就可以不用重新发jar包,让用jar包的人自己去扩展一个实现了工厂接口的具体工厂类即可)。完全符合封闭-扩展原则。

2.单例模式(Single Pattern)

释义:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。

故事理解:俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Sigleton,她们只要说道“老公”,都是指的同一个人,那就是我

常见实例:数据库创建时使用单例模式,Servlet环境下共享同一个资源或者对象

适用场景:对于定义的一个类,在整个应用程序执行期间只有唯一的一个实例对象。如Android中常见的Application对象。

单例模式可分为饿汉式,懒汉式等:

(一)饿汉式:其特点是应用中尚未需要用到此单一实例的时候即先实例化。

public class SingleTon {

    // 静态实例变量,直接初始化
    private static SingleTon instance = new SingleTon();

    // 私有化构造函数
    private SingleTon() {

    }

    // 静态public方法,向整个应用提供单例获取方式
    public static SingleTon getInstance() {
        return instance;
    }

}

(二)懒汉式:其特点是延迟加载,即当需要用到此单一实例的时候,才去初始化此单一实例。

public class SingletonA {    

    /**
     * 单例对象实例
     */
    private static SingletonA instance = null;    

    public static SingletonA getInstance() {
      if (instance == null) {     //line 12
          instance = new SingletonA();          //line 13
       }
        return instance;
    }
}

在这里要说下懒汉式,因为它具有一定的缺陷,我们可以假设这样的场景:两个线程并发调用Singleton.getInstance(),假设线程一先判断完instance是否为null,既代码中的line 12进入到line 13的位置。刚刚判断完毕后,JVM将CPU资源切换给线程二,由于线程一还没执行line 13,所以instance仍然是空的,因此线程二执行了new Signleton()操作。片刻之后,线程一被重新唤醒,它执行的仍然是new Signleton()操作。

所以对它进行了改良:

public class SingletonB {    

    /**
     * 单例对象实例
     */
    private static SingletonB instance = null;    

    public synchronized static SingletonB getInstance() {
      if (instance == null) {     //line 12
          instance = new SingletonB();          //line 13
       }
        return instance;
    }
}

往方法上加了个同步锁,这样就可以保证不会出线程问题了,但是这里有个很大(至少耗时比例上很大)的性能问题。除了第一次调用时是执行了SingletonB的构造函数之外,以后的每一次调用都是直接返回instance对象。返回对象这个操作耗时是很小的,绝大部分的耗时都用在synchronized修饰符的同步准备上,因此从性能上说很不划算。

所以又进行了改进:

public class SingletonC {  

    /**
     * 单例对象实例
     */
    private static SingletonKerriganD instance = null;  

    public static SingletonC getInstance() {
        if (instance == null) {
            synchronized (SingletonC.class) {
                if (instance == null) {
                    instance = new SingletonC();
                }
            }
        }
        return instance;
    }
}

目前我用的版本也就是这种。然而,网上有人又对这种单例模式进行了改进,因为还是存在缺陷,具体可以去网上拓展下。再说说饿汉式的写法,这种写法不会出现并发问题,在ClassLoader加载类后实例就会第一时间被创建。但饿汉式的创建方式在一些场景中将无法使用:譬如实例的创建是依赖参数或者配置文件的,在getInstance()之前必须调用某个方法设置参数给它,那样这种单例写法就无法使用了。

3.命令模式(Command Pattern)

释义:把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。

故事理解:俺有一个MM家里管得特别严,没法见面,只好借助于她弟弟在我们俩之间传送信息,她对我有什么指示,就写一张纸条让她弟弟带给我。这不,她弟弟又传送过来一个COMMAND,为了感谢他,我请他吃了碗杂酱面,哪知道他说:“我同时给我姐姐三个男朋友送COMMAND,就数你最小气,才请我吃面。

常见实例:常用的Runnable(在java.lang包下),其实就是用了命令模式,具体的体现过程,可见该博客

Runnable下的命令设计模式

适用场景:1. 命令的发送者和命令执行者有不同的生命周期。命令发送了并不是立即执行。2. 命令需要进行各种管理逻辑。3. 需要支持撤消\重做操作(这种状况的代码大家可以上网搜索下,有很多,这里不进行详细解读)。

其实经典的命令模式包括4个角色:

Command:定义命令的统一接口

ConcreteCommand:Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。

Receiver:命令的实际执行者

Invoker:命令的请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。

接下来,就以小菜大鸟去烧烤店,给服务员报菜,然后服务员通知厨师为例子。

Command类 :

/*
 * 抽象命令
 */
abstract class Command {
    protected Barbecuer barbecuer;  

    public Command(Barbecuer barbecuer) {
        this.barbecuer = barbecuer;
    }  

    // 执行命令
    public abstract void excuteCommand();
} 

(Receiver类)Barbecuer:

/*
 * 烤肉串者
 */
class Barbecuer {  

    // 烤羊肉串
    public void bakeMutton() {
        System.out.println("烤羊肉串!");
    }  

    // 烤鸡翅
    public void bakeChickenWing() {
        System.out.println("烤鸡翅!");
    }
} 

(ConcreteCommand类) BakeMuttonCommand、BakeChickenWingCommand:

/*
 * 烤羊肉串命令
 */
class BakeMuttonCommand extends Command {  

    public BakeMuttonCommand(Barbecuer barbecuer) {
        super(barbecuer);
    }  

    @Override
    public void excuteCommand() {
        barbecuer.bakeMutton();
    }  

    @Override
    public String toString() {
        return "命令模式,烤羊肉串命令!";
    }  

} 

/*
 * 烤鸡翅命令
 */
class BakeChickenWingCommand extends Command {  

    public BakeChickenWingCommand(Barbecuer barbecuer) {
        super(barbecuer);
    }  

    @Override
    public void excuteCommand() {
        barbecuer.bakeChickenWing();
    }  

    @Override
    public String toString() {
        return "命令模式,烤鸡翅命令!     ";
    }
}

(Invoker类)Waiter :

/*
 * 服务员
 */
class Waiter {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private List<Command> orders = new ArrayList<Command>();  

    // 设定订单
    public void setOrder(Command command) {
        orders.add(command);
        System.out.println("增加订单:" + command.toString() + " \t时间:" + simpleDateFormat.format(new Date()));
    }  

    // 取消订单
    public void cancelOrder(Command command) {
        orders.remove(command);
        System.out.println("取消订单:" + command.toString() + " \t时间:" + simpleDateFormat.format(new Date()));
    }  

    // 通知全部执行
    public void notifyA() {
        for (Command command : orders) {
            command.excuteCommand();
        }
    }
}  

Client类实现(如下):

public class CommandMode {
    public static void main(String[] args) {
        // 开店前准备
        Barbecuer boy = new Barbecuer();
        Command bakeMuttonCommand1 = new BakeMuttonCommand(boy);
        Command bakeMuttonCommand2 = new BakeMuttonCommand(boy);
        Command bakeChickenWingCommand = new BakeChickenWingCommand(boy);
        Waiter girl = new Waiter();  

        // 开门营业
        girl.setOrder(bakeMuttonCommand1);
        girl.setOrder(bakeMuttonCommand2);
        girl.setOrder(bakeChickenWingCommand);  

        // 点菜完毕,通知厨房
        girl.notifyA();
    }
}  

总结来说,命令模式是将功能提升到对象来操作,以便对多个功能进行一系列的处理以及封装。

这里要建议下命令模式的使用,当我们不清楚是否需要使用时,一般不用着急去实现它。事实上,在需要的时候通过重构实现这个模式并不困难,只有在真正需要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。

最后,设计模式的运用,有助于代码的维护与拓展。任何模式的出现,都是为了解决一些特定的场景的耦合问题,以达到对修改封闭,对扩展开放的效果。

六种模式,学习它们,提高自己!除了这六种,还有几种比较常用的,接下来会继续思考,继续熟悉!

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-21 23:14:30

Android常用设计模式(二)的相关文章

Android 常用设计模式(一)

由于项目变更的频繁性,作为一名程序员,我们需要掌握设计模式的必要性,就不言而喻~~,下面就是一些我自己学习的设计模式总结. 接下来,主要是针对几个比较常用模式进行讲解,主要是以下几种: 观察者模式 适配器模式 代理模式 工厂模式 单例模式 命令模式 1.观察者模式(Observer Pattern) 释义:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己. 故事理解:观察者想知道公司所有MM

Android常用设计模式

Android常用设计模式之观察者模式 观察者设计模式在Android应用中会经常用到,模式原理类似于这样的场景: 用户订报纸,然后在报社登记,报社来统计用户(添加用户),用户也可以取消订阅,报社删除用户:然后用户观察报社, 当有了新的报纸,报社就告诉用户并发送报纸的用户的手上,这其中,用户是观察者,报社是被观察者,一旦报纸有了新的 (数据发生改变)报社就会通知用户: 代码示例如下: 首先我们根据用户的共同特征,都要接受报纸,来提取出来一个公共的用户接口 1 /** 2 * 用户接口 3 * 4

Android常用界面布局(二)

ImageView ScaleType属性, 该属性用以表示显示图片的方式 ①matrix               根据一个3x3的矩阵对其中图片进行缩放 ②fitXY                  将图片非等比例缩放到大小与ImageView相同 ③fitStart               缩放方式同FIT_CENTER,只是将图片显示在左方或上方,而不是居中 ④fitCenter           ImageView的默认状态,大图等比例缩小,小图等比例放大,整体居中显示在Im

Android常用面试题大全

1.TCP和UDP之间的区别?什么是URL ? TCP被称为用户数据报协议;UDP被称为信息传输控制协议;URL被称为统一资源定位符,通过统一资源定位符可以唯一定位到互联网上的某个资源(图片.视频.音频和网页等). 2.成员方法和构造方法有什么区别? 成员方法必须有返回类型,即使是没有返回,也要写上void:构造函数没有返回类型,而且和类名一样. 3.什么是栈? 栈是一种先进后出的线性表,只要符合先进后出的原则的线性表都是栈.至于采用的存储方式(实现方式)是顺序存储(顺序栈)还是链式存储(链式栈

编程常用设计模式详解--(上篇)(工厂、单例、建造者、原型)

参考来自:http://zz563143188.iteye.com/blog/1847029 一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释器模式. 二.设计模式的六大原则 1

Android常用开源项目

Android常用开源项目 Android   2014-05-23 16:39:43 发布 您的评价:       4.3   收藏     24收藏 Android开源项目第一篇--个性化控件(View)篇  包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.其他Android开源项目第二篇--工具库篇  包括依赖注入.图片缓存.网络相关.数据库ORM工具包.Android公

Android学习笔记二十九之SwipeRefreshLayout、RecyclerView和CardView

Android学习笔记二十九之SwipeRefreshLayout.RecyclerView和CardView 前面我们介绍了AlertDialog和几个常用的Dialog,ProgressDialog进度条提示框.DatePickerDialog日期选择对话框和TimePickerDialog时间选择对话框.这一节我们介绍几个新的API控件SwipeRefreshLayout.RecyclerView和CardView,这几个API控件都是google在Android5.0推出的.下面我们来学

9款Android常用的快速开发框架

1.Afinal框架 项目地址:https://github.com/yangfuhai/afinal 项目地址:http://www.oschina.net/p/afinal 主要有四大模块: (1) 数据库模块:android中的orm框架,使用了线程池对sqlite进行操作. (2) 注解模块:android中的ioc框架,完全注解方式就可以进行UI绑定和事件绑定.无需findViewById和setClickListener等. (3) 网络模块:通过httpclient进行封装http

Android常用酷炫控件(开源项目)github地址汇总

转载一个很牛逼的控件收集贴... 第一部分 个性化控件(View) 主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar.TextView.ScrollView.TimeView.TipView.FlipView.ColorPickView.GraphView.UI Style 等等. 一.ListView android-pulltorefresh一个强大的拉动