Android经常使用设计模式(二)
继上一篇 Android经常使用设计模式(一)里认识了观察者。适配器。代理等三种模式,这一篇将会解说下面三种模式:
- 工厂模式
- 单例模式
- 命令模式
1.工厂模式(Factory Pattern)
工厂模式分为简单工厂模式。工厂方法模式以及抽象工厂模式
- 简单工厂模式:普通情况下,提供一个方法,方法的參数是一个标志位。依据标志位来创建不同的对象。这样调用的时候仅仅须要提供一个标志位就能够创建一个实现了接口的类。
- 工厂方法模式:将简单工厂模式的那个方法分开。不再是在工厂方法中依据标志位创建对象了。而是定义一个工厂接口。然后想创建几个不同类型的对象(即实现了同一接口的不同java类),就创建了几个不同类型的工厂。也就是创建的对象和创建对象的工厂是一一相应的。然后client调用的时候直接去实例化一个详细的对象工厂。创建相相应的对象。
- 抽象工厂模式:事实上这个名起的有点不知所云没有表达出这个模式的特点。
事实上这个模式就是工厂方法模式的略微扩展一下而已。工厂方法模式里面。一般一个工厂接口仅仅有一个方法。比方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();
}
}
总结来说,命令模式是将功能提升到对象来操作,以便对多个功能进行一系列的处理以及封装。
这里要建议下命令模式的使用,当我们不清楚是否须要使用时。一般不用着急去实现它。事实上,在须要的时候通过重构实现这个模式并不困难。仅仅有在真正须要如撤销/恢复操作等功能时,把原来的代码重构为命令模式才有意义。
最后,设计模式的运用。有助于代码的维护与拓展。不论什么模式的出现。都是为了解决一些特定的场景的耦合问题,以达到对改动封闭,对扩展开放的效果。
六种模式。学习它们,提高自己!
除了这六种。还有几种比較经常使用的。接下来会继续思考。继续熟悉。
Android经常使用设计模式(二)的更多相关文章
- [转] Android中的设计模式-备忘录模式
转自Android中的设计模式-备忘录模式 定义 备忘录设计模式的定义就是把对象的状态记录和管理委托给外界处理,用以维持自己的封闭性. 比较官方的定义 备忘录模式(Memento Pattern)又叫 ...
- Android 经常使用设计模式(一)
由于项目变更的频繁性,作为一名程序猿,我们须要掌握设计模式的必要性.就不言而喻~~.以下就是一些我自己学习的设计模式总结. 接下来,主要是针对几个比較经常使用模式进行解说,主要是以下几种: 观察者模式 ...
- 二维码合成,将苹果和安卓(ios和android)合成一个二维码,让用户扫描一个二维码就可以分别下载苹果和安卓的应用
因为公司推广的原因,没有合适的将苹果和安卓(ios和android)合成一个二维码的工具. 因为这个不难,主要是根据浏览器的UA进行判断,所以就自己开发了一个网站 网站名称叫:好推二维码 https ...
- Android APP压力测试(二)之Monkey信息自动收集脚本
Android APP压力测试(二) 之Monkey信息自动收集脚本 前言: 上一篇Monkey介绍基本搬抄官方介绍,主要是为了自己查阅方便.本文重点介绍我在进行Monkey时如何自动收集相关信息 ...
- Android项目实战(二十八):Zxing二维码实现及优化
前言: 多年之前接触过zxing实现二维码,没想到今日项目中再此使用竟然使用的还是zxing,百度之,竟是如此牛的玩意. 当然,项目中我们也许只会用到二维码的扫描和生成两个功能,所以不必下载完整的ja ...
- Android多线程分析之二:Thread的实现
Android多线程分析之二:Thread的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多线程分析之一 ...
- Android抓包方法(二)之Tcpdump命令+Wireshark
Android抓包方法(二) 之Tcpdump命令+Wireshark 前言 做前端测试,基本要求会抓包,会分析请求数据包,查看接口是否调用正确,数据返回是否正确,问题产生是定位根本原因等.学会抓包分 ...
- Android Contextual Menus之二:contextual action mode
Android Contextual Menus之二:contextual action mode 接上文:Android Contextual Menus之一:floating context me ...
- Android Animation学习(二) ApiDemos解析:基本Animators使用
Android Animation学习(二) ApiDemos解析:基本Animatiors使用 Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.O ...
随机推荐
- [LOJ] 分块九题 7
区间加法,区间乘法,单点查询. 洛谷线段树2 屡清加法乘法的关系,定义答案为 a*mut+add 对于整块: 新的乘w,mut和add都要乘w 新的加w,add加w //Stay foolish,st ...
- docker使用阿里云镜像仓库docker
1:阿里云docker仓库 https://dev.aliyun.com/search.html 2:进去注册帐号后,点击自己的管理中心. 3:在管理中心点击加速器,右边面板会有你的加速地址,右边面板 ...
- (6) openssl passwd(生成加密的密码)
该伪命令用于生成加密的密码 [root@docker121 ssl]# man -f passwd passwd (1) - update user's authentication tokens p ...
- Centos7 使用firewall管理防火墙
一.Centos7使用firewall的管理防火墙 1.firewalld基本使用 启动:systemctl start firewalld 关闭:systemctl stop firewalld 状 ...
- MySQL 优化 之 Copying to tmp table on disk
项目中遇到了慢查询问题 Sql语句 SELECT sum(price) AS price, `member_id` FROM `crm_upload` GROUP BY member_id ORDER ...
- linux网络原理
1.ipconfig命令使用 显示所有正在启动的网卡的详细信息或设定系统中网卡的IP地址. 某一块网卡信息 打开或者关闭某一块网卡 2.ifup和ifdown ifup和ifdown分别是加载网卡信息 ...
- (二)Robto Framewoek使用自己的python库
有时候找不到合适的库来完成自动化工作,则需要使用自己定义的python库.本文简单描述自建python库,以及在robotframework中的使用方法. 新建库目录 在C:\Python27\Lib ...
- c++值传递和引用及指针传递区别
以下程序各有何问题? ***************************************************************************************** ...
- hexo干货系列:(总纲)搭建独立博客初衷
前言 我是一名程序员,以前知识整理都是整理在为知笔记上,博客用的比较少,更别说是使用独立博客,因为不会... 2016年过年在家期间偶然的机会萌发了自己要搭建一个属于自己的独立博客的想法,于是就有了下 ...
- POJ 2195 Going Home【最小费用流 二分图最优匹配】
题目大意:一个n*m的地图,上面有一些人man(m)和数量相等的house(H) 图上的距离为曼哈顿距离 问所有人住进一所房子(当然一个人住一间咯)距离之和最短是多少? 思路:一个人一间房,明显是二分 ...