Android经典的设计模式
【单例模式】【Build模式】【原型模式】【工厂模式】【策略模式】【状态模式】【责任链模式】【解释器模式】【命令模式】【观察者模式】【备忘录模式】【迭代器模式】
【模板方法模式】【访问者模式】【中介者模式】【代理模式】【组合模式】【装饰模式】【享元模式】【外观模式】【桥接模式】
【单例模式】
当第一次加载Singleton类时不会初始化sInstance,只有在第一次调用Singleton的getInstance方法时才会导致sInstance被初始化。因此第一次调用getInstance方法会导致
虚拟机加载SingletonHolder类,这种方法不仅能够确保线程安全,也能够保证单例对象的唯一性,同时也延迟的单例的实例化,所以这是推荐使用的单例模式方式
public class Singleton {
private Singleton(){};
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
/**
* 静态内部类
*/
private static class SingletonHolder{
private static final Singleton sInstance = new Singleton();
} }
这个方法虽然好像也很不错,但是好像会出现什么双重检查锁定(DCL)失效。
单例如果持有Context,那么很容易引发内存泄漏,此时需要注意传递给单例对象的Context最好是Application Context。
public class MyImageLoader extends ImageLoader {
private static MyImageLoader instance; public static MyImageLoader getInstance() {
if (instance == null) {
synchronized (MyImageLoader.class) {
if (instance == null) {
instance = new MyImageLoader();
}
}
}
return instance;
} protected MyImageLoader() { }
}
源码模式中的LayoutInflater
【Build模式】
优点:拥有良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成的细节。
将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。
缺点:会产生多余的Builder对象以及Director对象,消耗内存。
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(topTitle)
.setView(settingView)
.setNegativeButton(R.string.ok, new DialogInterface.OnClickListener() { @Override
public void onClick(DialogInterface dialog, int which) {
String servAddr = mServAddrEt.getText().toString().trim();
String roomNo = mRoomNoEt.getText().toString().trim();
String hid = mHidEt.getText().toString().trim();
}
}).setPositiveButton(R.string.cancel, null).create();
dialog.show();
源码模式中dialog
【原型模式】
可以通过克隆来实现原型模式;
只有当通过new构造对象比较耗时或者说成本较高的时候,通过clone方法才能获得效率上的提升;
通过clone拷贝对象时并不会执行构造方法;
//浅拷贝,特点是只复制了一份引用,改变一个对象的集合个数,另一个的集合个数也会改变
public class comA implements Serializable, Cloneable {
... .... public Object clone() {
comA o = null;
try {
o = (comA ) super.clone();
o.text=this.text;
o.image=this.image;//一个集合
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
//深拷贝 对于引用型的字段也采用拷贝的形式,而不是单纯的引用,这样改变一个对象的集合的个数,另一个对象的集合的个数不会改变
//整型并不是一个对象,它是值类型,而不是引用类型,因此不需要克隆
public class comA implements Serializable, Cloneable {
... .... public Object clone() {
comA o = null;
try {
o = (comA ) super.clone();
o.text=this.text;//int 或String的话这一步可以省略
o.image=(ArrayList<String>)this.image.clone();//一个集合 或对象 这一步省略之后,就是浅引用了
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
源码模式中的克隆Clone()
【工厂模式】 (简单工厂模式,工厂方法模式,抽象工厂模式)
一:简单工厂模式:
public static Operation createOperate(string operate)
{
Operation oper = null;
switch (operate)
{
case "+":
{
oper = new OperationAdd();
break;
}
case "-":
{
oper = new OperationSub();
break;
}
case "*":
{
oper = new OperationMul();
break;
}
case "/":
{
oper = new OperationDiv();
break;
}
}
return oper;
}
}
调用工厂,需要createOperator("/"),就能返回除法运算符。
优点:客户端不需要修改代码。
缺点: 当需要增加新的运算类的时候,不仅需新加运算类,还要修改工厂类,违反了开闭原则。 前文提到的简单工厂模式跟工厂方法模式极为相似,区别是:简单工厂只有三个要素,他没有工厂接口,并且得到产品的方法一般是静态的。
因为没有工厂接口,所以在工厂实现的扩展性方面稍弱,可以算所工厂方法模式的简化版。
二:工厂方法模式: 解耦最好
//这种方法没有下面那个反射实现工厂的方便
interface Product { //也可以通过abstract来完成 //只有一个产品接口
public void productMethod();
} class ProductA implements Product { //产品需要多个
public void productMethod() {
System.out.println("产品");
}
} interface Factory { //只有一个工厂借口
public IProduct createProduct();
} class FactoryA implements Factory { //工厂也需要多个
public IProduct createProduct() {
return new ProductA();
}
} public class Client {
public static void main(String[] args) {
Factory factory = new FactoryA();
Product prodect = factory.createProduct();
prodect.productMethod();
}
}
这个和简单工厂有区别,简单工厂模式只有一个工厂,工厂方法模式对每一个产品都有相应的工厂
好处:增加一个运算类(例如N次方类),只需要增加运算类和相对应的工厂,两个类,不需要修改工厂类。
缺点:增加运算类,会修改客户端代码,工厂方法只是把简单工厂的内部逻辑判断移到了客户端进行。
//我比较喜欢用这种,扩展方便
public abstract class AudiFactory{
public abstract <T extends AudiCar>T createAudiCar(Class<T> clz);
} public class AudiCarFactory extends AudiFactory{ //工厂类用反射的方式来实现,只需要一个就可以满足多个产品的实现 @Override
public <T extends AudiCar> T createAudiCar(Class<T> clz) {
AudiCar car=null;
try {
car=(AudiCar)Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
// TODO: handle exception
}
return (T)car;
}
}
public abstract class AudiCar{
public abstract void drive();
}
public class AudiQ3 extends AudiCar{ @Override
public void drive() {
System.out.print("Q3 启动了");
}
}
public class AudiQ5 extends AudiCar{ @Override
public void drive() {
System.out.print("Q5 启动了");
}
}
public class AudiQ10 extends AudiCar{ @Override
public void drive() {
System.out.print("Q10 启动了");
}
}
public static void main(String[] args) {
AudiFactory factory =new AudiCarFactory();
AudiQ3 audiQ3=factory.createAudiCar(AudiQ3.class);
audiQ3.drive();
AudiQ5 audiQ5=factory.createAudiCar(AudiQ5.class);
audiQ5.drive();
AudiQ10 audiQ10=factory.createAudiCar(AudiQ10.class);
audiQ10.drive();
}
工厂方法模式有四个要素:
- 工厂接口。工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的。
- 工厂实现。在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。
- 产品接口。产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。
- 产品实现。实现产品接口的具体类,决定了产品在客户端中的具体行为。
三:抽象工厂模式: 用的比较少,对复杂的情况感觉很有用
interface ITire { //轮胎 比较特殊,有多个产品接口
public void show();
}
class NormalTire implements ITire {
public void show() {
System.out.println("普通轮胎");
}
}
class SUVTire implements ITire {
public void show() {
System.out.println("越野轮胎");
}
}
interface IEngine { //发动机 比较特殊,有多个产品接口
public void show();
} class DomesticEngine implements IEngine {
public void show() {
System.out.println("国产发动机");
}
}
class ImportEngine implements IEngine {
public void show() {
System.out.println("进口发动机");
}
} public abstract class CarFactory {
public abstract ITire createTire(); //生产轮胎
public abstract IEngine createEngine(); //生产发动机
}
class Q3Factory implements CarFactory{
public ITire createTire() {
return new NormalTire();
}
public IEngine createEngine() {
return new DomesticEngine();
}
}
class Q7Factory implements CarFactory{
public ITire createTire() {
return new SUVTire();
}
public IEngine createEngine() {
return new ImportEngine();
}
} public class Client {
public static void main(String[] args){
CarFactory factoryQ3 = new Q3Factory();
factoryQ3.createTire().show();
factoryQ3.createEngine().show(); CarFactory factoryQ7 = new Q7Factory();
factoryQ7.createTire().show();
factoryQ7.createEngine().show();
}
} 普通轮胎
国产发动机 越野轮胎
进口发动机
抽象工厂模式的优点
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。
抽象工厂模式的缺点
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。
适用场景
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。
总结
无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。
所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。
源码模式中onCreat()方法也是工厂模式
【策略模式】
抽象折扣类
public interface MemberStrategy {
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double calcPrice(double booksPrice);
} 初级会员折扣类
public class PrimaryMemberStrategy implements MemberStrategy { @Override
public double calcPrice(double booksPrice) { System.out.println("对于初级会员的没有折扣");
return booksPrice;
} } 中级会员折扣类
public class IntermediateMemberStrategy implements MemberStrategy { @Override
public double calcPrice(double booksPrice) { System.out.println("对于中级会员的折扣为10%");
return booksPrice * 0.9;
} } 高级会员折扣类
public class AdvancedMemberStrategy implements MemberStrategy { @Override
public double calcPrice(double booksPrice) { System.out.println("对于高级会员的折扣为20%");
return booksPrice * 0.8;
}
}
价格类
public class Price {
//持有一个具体的策略对象
private MemberStrategy strategy;
/**
* 构造函数,传入一个具体的策略对象
* @param strategy 具体的策略对象
*/
public Price(MemberStrategy strategy){
this.strategy = strategy;
} /**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
} 客户端
public class Client { public static void main(String[] args) {
//选择并创建需要使用的策略对象
MemberStrategy strategy = new AdvancedMemberStrategy();
//创建环境
Price price = new Price(strategy);
//计算价格
double quote = price.quote();
System.out.println("图书的最终价格为:" + quote);
} }
策略模式的优点:
(1)策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
(2)使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,
统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。
策略模式的缺点:
(1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。
(2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。
源码模式中动画中的时间插值器TimeInterpolator
【状态模式】
源码实现中对wifi状态的管理
【责任链模式】
来考虑这样一个功能:申请聚餐费用的管理。
很多公司都是这样的福利,就是项目组或者是部门可以向公司申请一些聚餐费用,用于组织项目组成员或者是部门成员进行聚餐活动。
申请聚餐费用的大致流程一般是:由申请人先填写申请单,然后交给领导审批,如果申请批准下来,领导会通知申请人审批通过,然后申请人去财务领取费用,如果没有批准下来,领导会通知申请人审批未通过,此事也就此作罢。
不同级别的领导,对于审批的额度是不一样的,比如,项目经理只能审批500元以内的申请;部门经理能审批1000元以内的申请;而总经理可以审核任意额度的申请。
也就是说,当某人提出聚餐费用申请的请求后,该请求会经由项目经理、部门经理、总经理之中的某一位领导来进行相应的处理,但是提出申请的人并不知道最终会由谁来处理他的请求,一般申请人是把自己的申请提交给项目经理,或许最后是由总经理来处理他的请求。
源码实现有dispatchTouchEvent等对事件的传递
【解释器模式】
源码实现有PMS对AndroidManifest.xml的解析
【命令模式】
源码实现有Android事件在底层逻辑转换成的NotifyArgs
【观察者模式】
实例描述:客户支付了订单款项,这时财务需要开具发票,出纳需要记账,配送员需要配货。
EventBus使用进阶比较好一点的Activity+Fragment及它们之间的数据交换
源码实现有listview的adapter也是属于观察者模式
【备忘录模式】
备忘录模式所涉及的角色有三个:备忘录(Memento)角色、发起人(Originator)角色、负责人(Caretaker)角色
源码实现有activity中的onSaveInstanceState()方法
【迭代器模式】
提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。
源码实现有数据库查询使用的Cursor
【模板方法模式】
其特点是封装流程
源码模式中AsyncTask和Activity的生命周期使用的都是模板方法模式
【访问者模式】
假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。
可以用来做报表,比如CEO和CTO检查工程师和产品经理的年终报表,看的是不同的方面。
可以用来在方法或一些View上添加注解@*******
【中介者模式】
适当地使用中介者模式可以避免同事类之间的过度耦合,使得各同事类之间可以相对独立地使用。
源码实现比较好的例子是Keyguard锁屏功能的实现
【代理模式】
代理就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用
源码模式中的ActivityManagerProxy代理类,代理的是ActivityManagerNative的子类ActivityManagerService
【组合模式】
操作系统的文件系统其实就是一种典型的组合模式
ViewGroup和view也是嵌套组合
【装饰模式】
例子:比如一个男孩的服装,可以对他进行便宜的衣服的装饰或贵的衣服的装饰
装饰模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,但不对对象本身进行增强。
在源码中的表现是ContextWrapper是装饰者,ContextImpl则是具体实现类;其实我们平时在Activity的onCreate的一些视图、数据的处理也是类似于装饰模式
装饰模式避免了类爆炸,一层一层地嵌套,
【享元模式】
享元模式是一种对象池的实现,其应用场景有如果有几十万人一起去抢火车票,如果不用享元模式,则要新建几十万个对象,其结果就是导致频繁GC,导致系统卡顿。
在源码中的实现,比较接近的是Handler消息机制。
【外观模式】
外观模式就是统一的接口封装,将子系统的逻辑,交互隐藏起来,为用户提供一个高层次的接口。这样即使子系统发生了变化,用户也不会感知,因为用户使用的是高层次的接口
一个简单的小例子 SDK很大概率会使用外观模式。
在源码中Context对开发者来说就是一个高层次的接口
【桥接模式】
比如喝咖啡,有大杯加糖,大杯不加糖,小杯加糖,小杯不加糖,实际上可以分为两种变化,一是大杯小杯,二是加糖不加糖。
源码中的Window与WindowManager属于桥接
Window为抽象接口,PhoneWindow为抽象部分的具体实现,WindowManager则是实现部分的基类,WindowManagerImpl为实现部分的具体逻辑实现,其使用的WindowManagerGlobal通过IWindowManager接口与WindowManagerService进行交互,并有WMS完成具体的窗口管理工作
Android经典的设计模式的更多相关文章
- Android经常使用设计模式(二)
继上一篇 Android经常使用设计模式(一)里认识了观察者.适配器.代理等三种模式,这一篇将会解说下面三种模式: 工厂模式 单例模式 命令模式 1.工厂模式(Factory Pattern) 工厂模 ...
- Android经典完美退出方法
Android经典完美退出方法,使用单例模式创建一个Activity管理对象,该对象中有一个Activity容器(具体实现自己处理,使用LinkedList等)专门负责存储新开启的每一个Activit ...
- 《Android源码设计模式》学习笔记之ImageLoader
微信公众号:CodingAndroid cnblog:http://www.cnblogs.com/angel88/ CSDN:http://blog.csdn.net/xinpengfei521 需 ...
- [转] Android中的设计模式-备忘录模式
转自Android中的设计模式-备忘录模式 定义 备忘录设计模式的定义就是把对象的状态记录和管理委托给外界处理,用以维持自己的封闭性. 比较官方的定义 备忘录模式(Memento Pattern)又叫 ...
- Android中的设计模式之观察者模式
参考 <设计模式:可复用面向对象软件的基础 >5.7 Observer 观察者 对象行为型模式 <设计模式解析> 18.4 Observer模式 <Android源码设计 ...
- Android 经常使用设计模式(一)
由于项目变更的频繁性,作为一名程序猿,我们须要掌握设计模式的必要性.就不言而喻~~.以下就是一些我自己学习的设计模式总结. 接下来,主要是针对几个比較经常使用模式进行解说,主要是以下几种: 观察者模式 ...
- Android经典项目开发之天气APP实例分享
原文:Android经典项目开发之天气APP实例分享 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/mzc186/article/details/5 ...
- Android使用的设计模式1——观察者模式
设计模式,对程序员来说是一个坎,想在程序员这条路走得更远,设计模式是你的必修课.从大学时代接触GoF到工作几年后重新看设计模式,每次感觉都不一样.这次想借着分析Android Framework源码的 ...
- [Android]GOF23种设计模式 & Android中的设计模式
GOF23种设计模式 设计原则: 1. 单一职责原则(SRP):就一个类而言,应该仅有一个引起它变化的原因 2. 开放-封闭原则(OCP):软件实体(类.模块.函数等)应该可以扩展,但是不可修改.即对 ...
随机推荐
- x01.os.22: ubuntu 常用设置
新组装了个 64 位电脑,i5 CPU,进入 ubuntu 后,又是一通搜索设置,整理如下,以备后用. 安装 .dep 包 sudo dpkg -i [filename.dep] 在 ubuntu 中 ...
- linux常用命令(1)cd命令
1 命令格式:cd [目录名]2 命令功能切换当前目录至dirName3 常用范例3.1 进入系统根目录cd /3.2 进入上级目录cd .. 或者 cd ..//3.3 进入当前用户主目录当前用 ...
- mono for android 用ISharedPreferences 进行状态保持 会话保持 应用程序首选项保存
由于项目需要 要保持用户登录状态 要进行状态保持 用途就好像asp.net的session一样 登录的时候进行保存 ISharedPreferences shared = GetSharedPrefe ...
- Xamarin.Android多界面
一.准备 开始学习本教程前必须先完成该教程http://www.cnblogs.com/yaozhenfa/p/xamarin_android_quickstart.html 否则将无法继续. 二.界 ...
- 整理Ajax的点点滴滴
最近看了下<Javascript高级程序设计>(第三版)关于Ajax部分,做了这篇笔记. 一.常规用法 第一步,创建XHR对象var xhr = new XMLHttpRequest(); ...
- [PHP源码阅读]array_pop和array_shift函数
上篇文章介绍了PHP添加元素到数组的函数,那么当然有从数组中删除元素.array_pop和array_shift只从数组的头或尾删除一个元素.经过阅读源码,发现这两个函数的实现都是调用了同一个函数-- ...
- java中文乱码解决之道(九)-----总结
乱码,我们前台展示的杀手,可能有些朋友和我的经历一样:遇到乱码先按照自己的经验来解决,如果没有解决就google,运气好一搜就可以解决,运气不好可能够你折腾一番了.LZ之所以写这个系列博客就是因为遇到 ...
- Node.js实现RESTful api,express or koa?
文章导读: 一.what's RESTful API 二.Express RESTful API 三.KOA RESTful API 四.express还是koa? 五.参考资料 一.what's R ...
- ABP源码分析三十六:ABP.Web.Api
这里的内容和ABP 动态webapi没有关系.除了动态webapi,ABP必然是支持使用传统的webApi.ABP.Web.Api模块中实现了一些同意的基础功能,以方便我们创建和使用asp.net w ...
- 解析大型.NET ERP系统 分布式应用模式设计与实现
C/S架构的应用程序,将一些复杂的计算逻辑由客户端转移到服务器端可以改善性能,同时也为了其它方面的控制..NET Remoting在局域网内调用的性能相当不错.ERP系统中基于.NET Remotin ...