本文将结合实际谈谈23种设计模式,每种设计模式涉及

站在用户的角度思考问题,与客户深入沟通,找到青冈网站设计与青冈网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都做网站、成都网站建设、成都外贸网站建设、企业官网、英文网站、手机端网站、网站推广、域名注册、网站空间、企业邮箱。业务覆盖青冈地区。
用这种方式进行介绍设计模式,旨在结合每天都在接触的Android实际项目开发更好地理解设计模式,拉近与设计模式的距离,同时在实际开发与重构中,思考可以应用的重构手段与设计模式,既能保证写出复用性与可靠性更高的代码,也是对如何利用重构与设计模式这两大支柱进行优雅编程的最佳实践与总结。
同时一次性以这种方式介绍23种设计模式,也是出于既然要使用一个模式,那么就应该要先知道这么一个模式的想法,四人帮的《设计模式》也是对经验的总结,但是有巨人托着你上去,又何必自己再摸黑造梯子。
重构不是本章的重点,因为这也是一个非常大的话题,这边只讨论实际项目中是否有存在一些能用设计模式进行改善的地方。
关于重构,这边也有写了一篇博文 重构:改善既有代码的设计 ,基本列举了《重构:改善既有代码的设计》中的各项要点,后续还会继续将《重构》中的手法与设计模式应用到实际项目中,有所总结之后会再写几篇实际应用的博文。
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
单一原则很简单,就是将一组相关性很高的函数、数据封装到一个类中。换句话说,一个类应该有职责单一。
开闭原则理解起来也不复杂,就是一个类应该对于扩展是开放的,但是对于修改是封闭的。在一开始编写代码时,就应该注意尽量通过扩展的方式实现新的功能,而不是通过修改已有的代码实现,否则容易破坏原有的系统,也可能带来新的问题,如果发现没办法通过扩展来实现,应该考虑是否是代码结构上的问题,通过重构等方式进行解决。
所有引用基类的地方必须能透明地使用其子类对象。本质上就是说要好好利用继承和多态,从而以父类的形式来声明变量(或形参),为变量(或形参)赋值任何继承于这个父类的子类。
依赖倒置主要是实现解耦,使得高层次的模块不依赖于低层次模块的具体实现细节。怎么去理解它呢,我们需要知道几个关键点:
在我们用的Java语言中,抽象就是指接口或者抽象类,二者都是不能直接被实例化;细节就是实现类,实现接口或者继承抽象类而产生的类,就是细节。使用Java语言描述就是:各个模块之间相互传递的参数声明为抽象类型,而不是声明为具体的实现类;
类之间的依赖关系应该建立在最小的接口上。其原则是将非常庞大的、臃肿的接口拆分成更小的更具体的接口。
一个对象应该对其他的对象有最少的了解.
假设类A实现了某个功能,类B需要调用类A的去执行这个功能,那么类A应该只暴露一个函数给类B,这个函数表示是实现这个功能的函数,而不是让类A把实现这个功能的所有细分的函数暴露给B。
确保单例类只有一个实例,并且这个单例类提供一个函数接口让其他类获取到这个唯一的实例。
如果某个类,创建时需要消耗很多资源,即new出这个类的代价很大;或者是这个类占用很多内存,如果创建太多这个类实例会导致内存占用太多。上述情况下就应该使用单例模式
// 单例对象
private static AdvertPresenter mInstance;
/** * 私有化构造函数 */
private AdvertPresenter(){
}
/** * 获取AdvertPresenter实例 * @return */
public static AdvertPresenter getInstance() {
if (mInstance == null) {
synchronized (AdvertPresenter.class) {
if (mInstance == null) {
mInstance = new AdvertPresenter();
}
}
}
return mInstance;
}//获取WindowManager服务引用 WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);
其内部就是通过单例的方式持有一个WindowManager并返回这个对象
项目中存在多次使用Random与Gson的操作,可以将Random与Gson对象封装成单例进行使用
将一个复杂对象的构造与它的表示分离,使得同样的构造过程可以创建不同的表示。
主要是在创建某个对象时,需要设定很多的参数(通过setter方法),但是这些参数必须按照某个顺序设定,或者是设置步骤不同会得到不同结果。
各类自定义Dialog
AlertDialog.Builer builder=new AlertDialog.Builder(context);
builder.setIcon(R.drawable.icon)
.setTitle("title")
.setMessage("message")
.setPositiveButton("Button1",
new DialogInterface.OnclickListener(){
public void onClick(DialogInterface dialog,int whichButton){
setTitle("click");
}
})
.create()
.show();暂无
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
可以在类的属性特别多,但是又要经常对类进行拷贝的时候可以用原型模式,这样代码比较简洁,而且比较方便。
拷贝时要注意浅拷贝与深拷贝
private HashMap getClonePointMap(Map map) {
HashMap clone = new HashMap<>();
if (map != null) {
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
String key = (String) entry.getKey();
PointBean pointBean = (PointBean) entry.getValue();
if (pointBean != null) {
//遍历map并将克隆对象放到新的map中
clone.put(key, pointBean.clone());
} else {
clone.put(key, null);
}
}
}
return clone;
}Intent intent = new Intent(Intent.ACTION_SENDTO, uri); //克隆副本 Intent copyIntent=(Intetn)shareIntent.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;
}
}public Object getSystemService(String name) {
if (getBaseContext() == null) {
throw new IllegalStateException("System services not available to Activities before onCreate()");
}
//........
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
//.......
return super.getSystemService(name);
}在getSystemService方法中就是用到了简单工厂模式,根据传入的参数决定创建哪个对象,由于这些对象以单例模式提前创建好了,所以此处不用new了,直接把单例返回就好。
//重构前
public class AdvertPresenter {
...
private void initAdvertManager() {
String[] platforms = mAdConfig.getAllPlatforms();
if (platforms != null && platforms.length > 0) {
int platformSize = platforms.length;
for (int i = 0; i < platformSize; i++) {
String platform = platforms[i];
if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_FACEBOOK)) {
FacebookAdvertManager fbAdManager = new FacebookAdvertManager();
mAdvertManager.put(AdvertConstant.AD_PLATFORM_FACEBOOK, fbAdManager);
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_ADMOB)) {
AdMobAdvertManager adMobAdvertManager = new AdMobAdvertManager();
mAdvertManager.put(AdvertConstant.AD_PLATFORM_ADMOB, adMobAdvertManager);
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_MOPUB)) {
MopubAdvertManager mopubAdvertManager = new MopubAdvertManager();
mAdvertManager.put(AdvertConstant.AD_PLATFORM_MOPUB, mopubAdvertManager);
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_ADX)) {
AdxAdvertManager mopubAdvertManager = new AdxAdvertManager();
mAdvertManager.put(AdvertConstant.AD_PLATFORM_ADX, mopubAdvertManager);
}
}
}
}
...
}
//重构后
public class BaseAdvertManager {
...
public static BaseAdvertManager create(String platform) {
if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_FACEBOOK)) {
return new FacebookAdvertManager();
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_MOPUB)) {
return new MopubAdvertManager();
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_ADX)) {
return new AdxAdvertManager();
} else if (platform.equalsIgnoreCase(AdvertConstant.AD_PLATFORM_ADMOB)) {
return new AdMobAdvertManager();
} else {
***return new NullAdvertManager();***//引入NULL对象
}
}
...
}
public class AdvertPresenter {
...
private void initAdvertManager() {
String[] platforms = mAdConfig.getAllPlatforms();
if (platforms != null && platforms.length > 0) {
int platformSize = platforms.length;
for (int i = 0; i < platformSize; i++) {
String platform = platforms[i];
mAdvertManager.put(platform, BaseAdvertManager.create(platform));
}
}
}
...
}是定义一个创建产品对象的工厂接口,让其子类决定实例化哪一个类,将实际创建工作推迟到子类当中。
public abstract class Product {
public abstract void method();
}
public class ConcreteProduct extends Prodect {
public void method(){
System.out.println("我是具体产品!");
}
}
public abstract class Factory{
public abstract Product createProduct();
}
public class ConcreteFactory extends Factory{
public Product createProduct(){
return new ConcreteProductA();
}
}我们在开发中会用到很多数据结构,比如ArrayList,HashMap等。我们先来看下Java中Collection部分的类集框架的简要UML图。
我们知道Iterator是迭代器,用来遍历一个集合中的元素。而不同的数据结构遍历的方式是不一样的,所以迭代器的实现也是不同的。使用工厂方法模式将迭代器的具体类型延迟到具体容器类中,比较灵活,容易扩展。
public interface Iterable {
/** * Returns an iterator over elements of type {@code T}. * * @return an Iterator. */
Iterator iterator();
//省略部分代码
}List和Set继承自Collection接口,Collection接口继承于Iterable接口。所以List和Set接口也需要继承并实现Iterable中的iterator()方法。然后我们常用的两个间接实现类ArrayList和HashSet中的iterator方法就给我们具体构造并返回了一个迭代器对象。
我们找到ArrayList类,查看iterator方法的实现。
@Override
public Iterator iterator() {
return new ArrayListIterator();
}ArrayListIterator类型定义如下:
private class ArrayListIterator implements Iterator {
/** Number of elements remaining in this iteration */
private int remaining = size;
/** Index of element that remove() would remove, or -1 if no such elt */
private int removalIndex = -1;
/** The expected modCount value */
private int expectedModCount = modCount;
public boolean hasNext() {
return remaining != 0;
}
@SuppressWarnings("unchecked") public E next() {
ArrayList ourList = ArrayList.this;
int rem = remaining;
if (ourList.modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (rem == 0) {
throw new NoSuchElementException();
}
remaining = rem - 1;
return (E) ourList.array[removalIndex = ourList.size - rem];
}
public void remove() {
Object[] a = array;
int removalIdx = removalIndex;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (removalIdx < 0) {
throw new IllegalStateException();
}
System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
a[--size] = null; // Prevent memory leak
removalIndex = -1;
expectedModCount = ++modCount;
}
}我们看到这个类实现了Iterator接口,接口的定义如下:
public interface Iterator {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}基本的结构也分析完了,接下来对号入座,看一看具体是如何实现工厂方法模式的。
Iterator————>Product ArrayListIteratorr————>ConcreteProduct
Iterable/List————>Factory ArrayList————>ConcreteFactory
工厂方法使一个类的实例化延迟到子类,对应着将迭代器Iterator的创建从List延迟到了ArrayList。这就是工厂方法模式。
暂无
为创建一组相关或者是相互依赖的对象提供一个接口,而不需要制定他们的具体类
抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象。
public abstract class AbstractProductA{
public abstract void method();
}
public abstract class AbstractProdectB{
public abstract void method();
}
public class ConcreteProductA1 extends AbstractProductA{
public void method(){
System.out.println("具体产品A1的方法!");
}
}
public class ConcreteProductA2 extends AbstractProductA{
public void method(){
System.out.println("具体产品A2的方法!");
}
}
public class ConcreteProductB1 extends AbstractProductB{
public void method(){
System.out.println("具体产品B1的方法!");
}
}
public class ConcreteProductB2 extends AbstractProductB{
public void method(){
System.out.println("具体产品B2的方法!");
}
}
public abstract class AbstractFactory{
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}
public class ConcreteFactory1 extends AbstractFactory{
public AbstractProductA createProductA(){
return new ConcreteProductA1();
}
public AbstractProductB createProductB(){
return new ConcreteProductB1();
}
}
public class ConcreteFactory2 extends AbstractFactory{
public AbstractProductA createProductA(){
return new ConcreteProductA2();
}
public AbstractProductB createProductB(){
return new ConcreteProductB2();
}
}由于该模式存在的局限性,Android中很少有用到这个模式的地方,com.android.internal.policy包下的IPolicy有使用到这个模式,它是关于Android窗口,窗口管理,布局加载,以及事件回退Handler这一系列窗口相关产品的抽象工厂,但是其在源码中其实也只有一个具体的工厂实现。因为这部分结构较为复杂,代码量大,有兴趣的同学可以自己去查看相关资料或者阅读源码。
使用
区别
优点
缺点
由于抽象工厂不易于拓展新的产品族,所以这种设计模式,在提供对外部人员访问时,很少使用,也有人说抽象工厂方法模式是一种很“恶心”的设计模式,运用最为典范的一个是该模式最初的目的,也就是为了适应Unit和Windows两个操作系统下的视图而构建视图族,视图族有各自不同的实现;另一个就是Java连接数据库的操作中,对不同的数据库的操作而形成的的对象操作族,但是当再次更换数据时,所需要造成的接口的修改也十分麻烦,所以扩展性不好
暂无
有一系列的算法,将每个算法封装起来(每个算法可以封装到不同的类中),各个算法之间可以替换,策略模式让算法独立于使用它的客户而独立变化。
public abstract class BaseAdvertManager {
protected abstract void doLoadAdvert();
}
public class FacebookAdvertManager extends BaseAdvertManager {
@Override
protected void doLoadAdvert() {
Log.v(TAG, "加载Facebook广告");
}
}
public class AdmobAdvertManager extends BaseAdvertManager {
@Override
protected void doLoadAdvert() {
Log.v(TAG, "加载Admob广告");
}
}Android在属性动画中使用时间插值器的时候就用到了策略模式。在使用动画时,你可以选择线性插值器LinearInterpolator、加速减速插值器AccelerateDecelerateInterpolator、减速插值器DecelerateInterpolator以及自定义的插值器。这些插值器都是实现根据时间流逝的百分比来计算出当前属性值改变的百分比。通过根据需要选择不同的插值器,实现不同的动画效果。
暂无
状态模式中,行为是由状态来决定的,不同状态下有不同行为。状态模式和策略模式的结构几乎是一模一样的,主要是他们表达的目的和本质是不同。
public interface TvState{
public void nextChannerl();
public void prevChannerl();
public void turnUp();
public void turnDown();
}
public class PowerOffState implements TvState{
public void nextChannel(){}
public void prevChannel(){}
public void turnUp(){}
public void turnDown(){}
}
public class PowerOnState implements TvState{
public void nextChannel(){
System.out.println("下一频道");
}
public void prevChannel(){
System.out.println("上一频道");
}
public void turnUp(){
System.out.println("调高音量");
}
public void turnDown(){
System.out.println("调低音量");
}
}
public interface PowerController{
public void powerOn();
public void powerOff();
}
public class TvController implements PowerController{
TvState mTvState;
public void setTvState(TvStete tvState){
mTvState=tvState;
}
public void powerOn(){
setTvState(new PowerOnState());
System.out.println("开机啦");
}
public void powerOff(){
setTvState(new PowerOffState());
System.out.println("关机啦");
}
public void nextChannel(){
mTvState.nextChannel();
}
public void prevChannel(){
mTvState.prevChannel();
}
public void turnUp(){
mTvState.turnUp();
}
public void turnDown(){
mTvState.turnDown();
}
}
public class Client{
public static void main(String[] args){
TvController tvController=new TvController();
tvController.powerOn();
tvController.nextChannel();
tvController.turnUp();
tvController.powerOff();
//调高音量,此时不会生效
tvController.turnUp();
}
}Android源码中很多地方都有用到状态模式,举一个例子,就是Android的WIFI管理模块。当WIFI开启时,自动扫描周围的接入点,然后以列表的形式展示;当wifi关闭时则清空。这里wifi管理模块就是根据不同的状态执行不同的行为。
状态模式的行为是平行的、不可替换的,策略模式是属于对象的行为模式,其行为是彼此独立可相互替换的。
项目中有需要功能如瘦脸等存在开关,现在是通过配置文件进行判断,可以通过状态模式进行重构,进而在具体处理图片时可以利用多态的特性直接使用对象进行处理
使多个对象都有机会处理请求,从而避免请求的发送者和接受者直接的耦合关系,将这些对象连成一条链,并沿这条链传递该请求,直到有对象处理它为止。
/** * 抽象处理者 */
public abstract class Handler {
/** * 持有后继的责任对象 */
protected Handler successor;
/** * 示意处理请求的方法,虽然这个示意方法是没有传入参数的 * 但实际是可以传入参数的,根据具体需要来选择是否传递参数 */
public abstract void handleRequest();
/** * 取值方法 */
public Handler getSuccessor() {
return successor;
}
/** * 赋值方法,设置后继的责任对象 */
public void setSuccessor(Handler successor) {
this.successor = successor;
}
}
/** * 具体处理者 */
public class ConcreteHandler extends Handler {
/** * 处理方法,调用此方法处理请求 */
@Override public void handleRequest() {
/** * 判断是否有后继的责任对象 * 如果有,就转发请求给后继的责任对象 * 如果没有,则处理请求 */
if(getSuccessor() != null)
{
System.out.println("放过请求");
getSuccessor().handleRequest();
}else
{
System.out.println("处理请求");
}
}
}
/** * 发起请求的客户类 */
public class Client {
public static void main(String[] args) {
//组装责任链
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
//提交请求
handler1.handleRequest();
}
}在Android处理点击事件时,父View先接收到点击事件,如果父View不处理则交给子View,把责任依次往下传递;还有Java的异常捕获机制也是责任链模式的一种体现
暂无
给定一个语言,定义它的语法,并定义一个解释器,这个解释器用于解析语言。
如编写各种功能模块的配置文件,然后按照项目定义的配置文件编写规则在运行过程中将配置文件加载为配置对象,这个模式在日常项目中应该或多或少都会使用到,就不贴出代码了。
这个用到的地方也不少,其一就是Android的四大组件需要在AndroidManifest.xml中定义,其实AndroidManifest.xml就定义了,等标签(语句)的属性以及其子标签,规定了具体的使用(语法),通过PackageManagerService(解释器)进行解析。
暂无
命令模式将每个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;将请求进行排队或者记录请求日志,以及支持可撤销操作。
举个例子来理解:当我们点击“关机”命令,系统会执行一系列操作,比如暂停事件处理、保存系统配置、结束程序进程、调用内核命令关闭计算机等等,这些命令封装从不同的对象,然后放入到队列中一个个去执行,还可以提供撤销操作。
public void method() {
Handler.post(new Runnable() {
@Override
public void run() {
clearCache();
statics();
finish();
}
});
}在Android事件机制中,底层逻辑对事件的转发处理。每次的按键事件会被封装成NotifyKeyArgs对象,通过InputDispatcher封装具体的事件操作。还有一个例子就是我们使用的Runnable,我们可以使用它来封装自己想做的操作,然后交给Handler按顺序处理,或者在处理前remove取消掉
现在的广告模块业务逻辑可以进行这种模式的重构,将广告拉取、广告展示等请求都封装成一个个的对象,放入到一个管理容器中按照一定规则进行调用,这样不仅可以避免在调用了展示广告接口的时候正在拉取广告,进而导致展示次数丢失的情况,也可以在出现网络错误等异常情况时可以对一些步骤进行取消。
有时被称作发布/订阅模式,其定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
Java的Observable类和Observer接口就是实现了观察者模式。一个Observer对象监视着一个Observable对象的变化,当Observable对象发生变化时,Observer得到通知,就可以进行相应的工作。
感兴趣的可以直接去查看两个类的源码,这个模式比较常用,就不在这里再贴一次了。
ListView的适配器有个notifyDataSetChange()函数,就是通知ListView的每个Item,数据源发生了变化,各个子Item需要重新刷新一下。
比如现在相机选完滤镜拍照后进入自拍确认页,这时候如果用户更换了滤镜,那么回来的时候应该把相机界面的滤镜替换为最新选择的滤镜。目前是在相机界面的onResume函数里做这个逻辑,但是其实可以把滤镜抽成一个完整的模块,然后在模块内部自己实现观察者模式,这样一方面把滤镜的逻辑封装起来,与外界解耦,也符合Java多用组合的理念
EventBus的好处很明显,可以很方便简单地实现观察者模式,但是坏处也很明显
所以如果出现了需要使用观察者模式的情况,在各方面条件允许的情况下,建议还是在这个模块中自己实现观察者模式,如果发现这个功能在其他模块也需要,那么就要考虑是不是应该把这系列功能抽成一个更加独立的模块从而进行复用,而不是贪图方便地直接使用EventBus
在不破坏封闭的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态,这样,以后就可将对象恢复到原先保存的状态中。
序列化对象到本地并在必要时将对象反序列化恢复回来
public PhotoData readPhotoData(String path) {
PhotoData photoData = null;
ObjectInputStream objInput = null;
try {
objInput = new ObjectInputStream(new FileInputStream(path));
photoData = (PhotoData) objInput.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (objInput != null) {
objInput.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return photoData;
}
public void writePhotoData(PhotoData data, String path) {
ObjectOutputStream objOutput = null;
try {
objOutput = new ObjectOutputStream(new FileOutputStream(path));
objOutput.writeObject(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (objOutput != null) {
objOutput.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}Activity的onSaveInstanceState和onRestoreInstanceState就是用到了备忘录模式,分别用于保存和恢复。
暂无
提供一种方法顺序访问一个容器对象中的各个元素,而不需要暴露该对象的内部表示。
迭代器模式是与集合共生共死的,一般来说,我们只要实现一个集合,就需要同时提供这个集合的迭代器,就像java中的Collection,List、Set、Map等,这些集合都有自己的迭代器。假如我们要实现一个这样的新的容器,当然也需要引入迭代器模式,给我们的容器实现一个迭代器。
Java的Iterator就是一个抽象迭代器,通过实现这个接口各个集合可以提供自己定制的具体迭代器,感兴趣的可以直接查看源码
虽然我们使用集合的场景非常多,但是实际使用到迭代器的却比较少,对于比较简单的遍历(像数组或者有序列表),使用迭代器方式遍历较为繁琐,比如ArrayList,我们更倾向于使用for循环来遍历,但是针对hash表之类的集合来说,引入迭代器就反而简单多了。同时我们也可以通过自定义迭代器来对有序列表提供正序遍历或者倒序遍历,用户只需要得到迭代器就可以遍历了,而不需要关心具体遍历算法。
Android源码中,最典型的就是Cursor用到了迭代器模式,当我们使用SQLiteDatabase的query方法时,返回的就是Cursor对象,之后再通过Cursor去遍历数据
暂无
定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。
public abstract class BaseAdvertManager {
public void loadAdvert(Context context, int type) {
if (NetUtils.checkNetConnection(context) != NetUtils.OK) {
return;
}
mStateArray.put(type, AdvertConstant.AD_STATE_LOADING);
doLoadAdvert(context, type);
}
protected abstract void doLoadAdvert(Context context, int type);
}广告管理器抽象类定义了加载广告的通用模板,但是又把模板中具体加载广告的逻辑声明为抽象方法为各个子类自我实现
启动一个Activity过程非常复杂,有很多地方需要开发者定制,也就是说,整体算法框架是相同的,但是将一些步骤延迟到子类中,比如Activity的onCreate、onStart等等。这样子类不用改变整体启动Activity过程即可重定义某些具体的操作了。
大部分代码相同部分代码不同的方法都可以尝试使用模板方法重构,要么是在同一个类里面进行方法的重构,要么通过塑造模板函数的重构手段对子类与父类进行重构
项目中自拍确认页保存照片并分享与保存照片并后退目前是两个独立的方法,但是方法内部大多数代码都是一样的,就需要用该模式进行重构,由于代码量大而且该重构手段比较简单,就不贴出代码
封装一些作用于某种数据结构中各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。
假如一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去。
访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
访问者模式是23种设计模式中最复杂最难理解的一个,但他的使用率并不高,大部分情况下,我们不需要使用访问者模式,少数特定的场景才需要。
大多数情况下,你并需要使用访问者模式,但是当你一旦需要使用它时,那你就是真的需要它了。——GOF《设计模式:可复用面向对象软件的基础 》
interface Service {
public void accept(Visitor visitor);
}
class Draw implements Service {
public void accept(Visitor visitor) {
visitor.process(this);
}
}
class Fund implements Service {
public void accept(Visitor visitor) {
visitor.process(this);
}
}
class Saving implements Service {
public void accept(Visitor visitor) {
visitor.process(this);
}
}
class Visitor {
public void process(Service service) {
// 基本业务
System.out.println("基本业务");
}
public void process(Saving service) {
// 存款
System.out.println("存款");
}
public void process(Draw service) {
// 提款
System.out.println("提款");
}
public void process(Fund service) {
System.out.println("基金");
// 基金
}
}
public class Client {
public static void main(String[] args){
Service saving = new Saving();
Service fund = new Fund();
Service draw = new Draw();
Visitor visitor = new Visitor();
saving.accept(visitor);
fund.accept(visitor);
draw.accept(visitor);
}
}采用Visitor的好处如上面所示,当需要改变其中一项业务的处理时,不需要每个地方都进行修改,而只需要改动Visitor类中相应的处理函数就可以了。也就是说它适合于业务处理时常发生变动的情况。
当然,Visitor也有它自身的限制。它不适合于业务数量的经常变化,因为一旦新增或删除一些Service时,需要对Visitor进行相应的增删。也就是说具体Service与Visitor是耦合的。
Android中运用访问者模式,其实主要是在编译期注解中,编译期注解核心原理依赖APT(Annotation Processing Tools),著名的开源库比如ButterKnife、Dagger、Retrofit都是基于APT。
如果是一些经常需要变动逻辑的业务则非常适合使用访问者模式,如果是需要频繁增加新的业务的,则不适合,所以Android的UI展示部分其实理论上来说是适合使用访问者模式的,因为UI常常一个版本一个变化,如果当UI的变化不只是局限在XML中修修改改的话,而是已经体现在了代码中,那么可以考虑是否可以使用访问者模式进行修改。
目前实际项目中暂无这种情况,广告模块后续的UI渲染由于是根据不同的广告平台所下发的广告对象来进行对应的渲染,目前每个广告平台渲染视图的接口所需参数不太一样,但是可以考虑进行一下抽离封装,做成一个简单的Visitor试试看。
中介者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显调用,从而使他们可以轻松耦合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用保证这些作用可以彼此独立的变化,中介者模式将多对多的相互作用转为一对多的相互作用。
其实,中介者对象是将系统从网状结构转为以调停者为中心的星型结构。
举个简单的例子,一台电脑包括:CPU、内存、显卡、IO设备。其实,要启动一台计算机,有了CPU和内存就够了。当然,如果你需要连接显示器显示画面,那就得加显卡,如果你需要存储数据,那就要IO设备,但是这并不是最重要的,它们只是分割开来的普通零件而已,我们需要一样东西把这些零件整合起来,变成一个完整体,这个东西就是主板。主板就是起到中介者的作用,任何两个模块之间的通信都会经过主板协调。
public abstract class Person {
protected String name;
protected Mediator mediator;
Person(String name,Mediator mediator){
this.name = name;
this.mediator = mediator;
}
}
public class HouseOwner extends Person{
HouseOwner(String name, Mediator mediator) {
super(name, mediator);
}
/** * @desc 与中介者联系 * @param message * @return void */
public void constact(String message){
mediator.constact(message, this);
}
/** * @desc 获取信息 * @param message * @return void */
public void getMessage(String message){
System.out.println("房主:" + name +",获得信息:" + message);
}
}
public class Tenant extends Person{
Tenant(String name, Mediator mediator) {
super(name, mediator);
}
/** * @desc 与中介者联系 * @param message * @return void */
public void constact(String message){
mediator.constact(message, this);
}
/** * @desc 获取信息 * @param message * @return void */
public void getMessage(String message){
System.out.println("租房者:" + name +",获得信息:" + message);
}
}
public abstract class Mediator {
//申明一个联络方法
public abstract void constact(String message,Person person);
}
public class MediatorStructure extends Mediator{
//首先中介结构必须知道所有房主和租房者的信息
private HouseOwner houseOwner;
private Tenant tenant;
public HouseOwner getHouseOwner() {
return houseOwner;
}
public void setHouseOwner(HouseOwner houseOwner) {
this.houseOwner = houseOwner;
}
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
public void constact(String message, Person person) {
if(person == houseOwner){ //如果是房主,则租房者获得信息
tenant.getMessage(message);
}
else{ //反正则是房主获得信息
houseOwner.getMessage(message);
}
}
}
public class Client {
public static void main(String[] args) {
//一个房主、一个租房者、一个中介机构
MediatorStructure mediator = new MediatorStructure();
//房主和租房者只需要知道中介机构即可
HouseOwner houseOwner = new HouseOwner("张三", mediator);
Tenant tenant = new Tenant("李四", mediator);
//中介结构要知道房主和租房者
mediator.setHouseOwner(houseOwner);
mediator.setTenant(tenant);
tenant.constact("听说你那里有三室的房主出租.....");
houseOwner.constact("是的!请问你需要租吗?");
}
}房主:张三,获得信息:听说你那里有三室的房主出租…..
租房者:李四,获得信息:是的!请问你需要租吗?
在Binder机制中,就用到了中介者模式。我们知道系统启动时,各种系统服务会向ServiceManager提交注册,即ServiceManager持有各种系统服务的引用 ,当我们需要获取系统的Service时,比如ActivityManager、WindowManager等(它们都是Binder),首先是向ServiceManager查询指定标示符对应的Binder,再由ServiceManager返回Binder的引用。并且客户端和服务端之间的通信是通过Binder驱动来实现,这里的ServiceManager和Binder驱动就是中介者。
从年初开始就有在项目里面做MVP的重构,MVP架构里面P层其实就是一个中介者,负责协调V和M
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。
举个例子,我们在启动计算机时,只需按一下开关键,无需关系里面的磁盘、内存、cpu、电源等等这些如何工作,我们只关心他们帮我启动好了就行。实际上,由于里面的线路太复杂,我们也没办法去具体了解内部电路如何工作。主机提供唯一一个接口“开关键”给用户就好。
/** * cpu子系统类 */
public class CPU {
public static final Logger LOGGER = Logger.getLogger(CPU.class);
public void start() {
LOGGER.info("cpu is start...");
}
public void shutDown() {
LOGGER.info("CPU is shutDown...");
}
}
/** * Disk子系统类 */
public class Disk {
public static final Logger LOGGER = Logger.getLogger(Disk.class);
public void start() {
LOGGER.info("Disk is start...");
}
public void shutDown() {
LOGGER.info("Disk is shutDown...");
}
}
/** * Memory子系统类 */
public class Memory {
public static final Logger LOGGER = Logger.getLogger(Memory.class);
public void start() {
LOGGER.info("Memory is start...");
}
public void shutDown() {
LOGGER.info("Memory is shutDown...");
}
}
/** * 门面类(核心) */
public class Computer {
public static final Logger LOGGER = Logger.getLogger(Computer.class);
private CPU cpu;
private Memory memory;
private Disk disk;
public Computer() {
cpu = new CPU();
memory = new Memory();
disk = new Disk();
}
public void start() {
LOGGER.info("Computer start begin");
cpu.start();
disk.start();
memory.start();
LOGGER.info("Computer start end");
}
public void shutDown() {
LOGGER.info("Computer shutDown begin");
cpu.shutDown();
disk.shutDown();
memory.shutDown();
LOGGER.info("Computer shutDown end...");
}
}
/** * 客户端类 */
public class Cilent {
public static final Logger LOGGER = Logger.getLogger(Cilent.class);
public static void main(String[] args) {
Computer computer = new Computer();
computer.start();
LOGGER.info("=================");
computer.shutDown();
}
}从上面的实例来看,有了这个Facade类,也就是Computer类,用户就不用亲自去调用子系统中的Disk,Memory、CPU类了,不需要知道系统内部的实现细节,甚至都不用知道系统内部的构成。客户端只需要跟Facade交互就可以了。
那么Android哪里使用到了外观模式呢?依然回到Context,Android内部有很多复杂的功能比如startActivty、sendBroadcast、bindService等等,这些功能内部的实现非常复杂,如果你看了源码你就能感受得到,但是我们无需关心它内部实现了什么,我们只关心它帮我们启动Activity,帮我们发送了一条广播,绑定了Activity等等就够了。
暂无
给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
代理模式有几种,虚拟代理,计数代理,远程代理,动态代理。主要分为两类,静态代理和动态代理。
静态代理比较简单,是由程序员编写的代理类,并在程序运行前就编译好的,而不是由程序动态产生代理类,这就是所谓的静态。可以通过聚合和继承两种方式实现,继承方式不够灵活,所以只介绍聚合的方式
nterface Subject {
void request();
}
class RealSubject implements Subject {
public void request(){
System.out.println("RealSubject");
}
}
class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("begin");
subject.request();
System.out.println("end");
}
}
public class ProxyTest {
public static void
本文标题:谈谈23种设计模式在Android项目中的应用
文章网址:http://cdysf.com/article/djjjdpj.html