Android应用开发中控制反转IoC设计模式使用教程

1、概述
首先我们来吹吹牛,什么叫IoC,控制反转(Inversion of Control,英文缩写为IoC),什么意思呢?
就是你一个类里面需要用到很多个成员变量,传统的写法,你要用这些成员变量,那么你就new 出来用呗~~
IoC的原则是:NO,我们不要new,这样耦合度太高;你配置个xml文件,里面标明哪个类,里面用了哪些成员变量,等待加载这个类的时候,我帮你注入(new)进去;
这样做有什么好处呢?
 回答这个问题,刚好可以回答另一个问题,很多人问,项目分层开发是吧,分为控制层、业务层、DAO层神马的。然后每一层为撒子要一个包放接口,一个包放实现呢?只要一个实现包不行么~刚好,如果你了解了IoC,你就知道这些个接口的作用了,上面不是说,你不用new,你只要声明了成员变量+写个配置文件,有人帮你new;此时,你在类中,就可以把需要使用到的成员变量都声明成接口,然后你会发现,当实现类发生变化的时候,或者切换实现类,你需要做什么呢?你只要在配置文件里面做个简单的修改。如果你用的就是实实在在的实现类,现在换实现类,你需要找到所有声明这个实现类的地方,手动修改类名;如果你遇到了一个多变的老大,是吧,呵呵~
 当然了,很多会觉得,写个配置文件,卧槽,这多麻烦。于是乎,又出现了另一种方案,得,你闲配置文件麻烦,你用注解吧。你在需要注入的成员变量上面给我加个注解,例如:@Inject,这样就行了,你总不能说这么个单词麻烦吧~~
 当然了,有了配置文件和注解,那么怎么注入呢?其实就是把字符串类路径变成类么,当然了,反射上场了;话说,很久很久以前,反射很慢啊,嗯,那是很久很久以前,现在已经不是太慢了,当然了肯定达不到原生的速度~~无反射,没有任何框架。
 如果你觉得注解,反射神马的好高级。我说一句:Just Do It ,你会发现注解就和你写一个普通JavaBean差不多;反射呢?API就那么几行,千万不要被震慑住~

2、框架实现
得进入正题了,Android IOC框架,其实主要就是帮大家注入所有的控件,布局文件什么的。如果你用过xUtils,afinal类的框架,你肯定不陌生~
注入View
假设:我们一个Activity,里面10来个View。
传统做法:我们需要先给这个Activity设置下布局文件,然后在onCreate里面一个一个的findViewById把~
目标的做法:Activity类上添加个注解,帮我们自动注入布局文科;声明View的时候,添加一行注解,然后自动帮我们findViewById;
于是乎我们的目标类是这样的:

@ContentView(value = R.layout.activity_main)
public class MainActivity extends BaseActivity
{
 @ViewInject(R.id.id_btn)
 private Button mBtn1;
 @ViewInject(R.id.id_btn02)
 private Button mBtn2;

3、编码
(1)定义注解
首先我们需要两个注解文件:

package com.zhy.ioc.view.annotation; 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView
{
 int value();
}

ContentView用于在类上使用,主要用于标明该Activity需要使用的布局文件。

 @ContentView(value = R.layout.activity_main)
public class MainActivity 

package com.zhy.ioc.view.annotation; 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject
{
 int value();
}

在成员变量上使用,用于指定View的Id

@ViewInject(R.id.id_btn)
 private Button mBtn1;

简单说一下注解:定义的关键字@interface ; @Target表示该注解可以用于什么地方,可能的类型TYPE(类),FIELD(成员变量),可能的类型:

public enum ElementType {
 /**
  * Class, interface or enum declaration.
  */
 TYPE,
 /**
  * Field declaration.
  */
 FIELD,
 /**
  * Method declaration.
  */
 METHOD,
 /**
  * Parameter declaration.
  */
 PARAMETER,
 /**
  * Constructor declaration.
  */
 CONSTRUCTOR,
 /**
  * Local variable declaration.
  */
 LOCAL_VARIABLE,
 /**
  * Annotation type declaration.
  */
 ANNOTATION_TYPE,
 /**
  * Package declaration.
  */
 PACKAGE
}

就是这些个枚举。
@Retention表示:表示需要在什么级别保存该注解信息;我们这里设置为运行时。
可能的类型:

public enum RetentionPolicy {
 /**
  * Annotation is only available in the source code.
  */
 SOURCE,
 /**
  * Annotation is available in the source code and in the class file, but not
  * at runtime. This is the default policy.
  */
 CLASS,
 /**
  * Annotation is available in the source code, the class file and is
  * available at runtime.
  */
 RUNTIME
}

这些个枚举~

(2)MainActivity

package com.zhy.zhy_xutils_test; 

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast; 

import com.zhy.ioc.view.ViewInjectUtils;
import com.zhy.ioc.view.annotation.ContentView;
import com.zhy.ioc.view.annotation.ViewInject; 

@ContentView(value = R.layout.activity_main)
public class MainActivity extends Activity implements OnClickListener
{
 @ViewInject(R.id.id_btn)
 private Button mBtn1;
 @ViewInject(R.id.id_btn02)
 private Button mBtn2; 

 @Override
 protected void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState); 

  ViewInjectUtils.inject(this); 

  mBtn1.setOnClickListener(this);
  mBtn2.setOnClickListener(this);
 } 

 @Override
 public void onClick(View v)
 {
  switch (v.getId())
  {
  case R.id.id_btn:
   Toast.makeText(MainActivity.this, "Why do you click me ?",
     Toast.LENGTH_SHORT).show();
   break; 

  case R.id.id_btn02:
   Toast.makeText(MainActivity.this, "I am sleeping !!!",
     Toast.LENGTH_SHORT).show();
   break;
  }
 } 

}

注解都写好了,核心的代码就是ViewInjectUtils.inject(this)了~

(3)ViewInjectUtils
A、首先是注入主布局文件的代码:

/**
  * 注入主布局文件
  *
  * @param activity
  */
 private static void injectContentView(Activity activity)
 {
  Class<? extends Activity> clazz = activity.getClass();
  // 查询类上是否存在ContentView注解
  ContentView contentView = clazz.getAnnotation(ContentView.class);
  if (contentView != null)// 存在
  {
   int contentViewLayoutId = contentView.value();
   try
   {
    Method method = clazz.getMethod(METHOD_SET_CONTENTVIEW,
      int.class);
    method.setAccessible(true);
    method.invoke(activity, contentViewLayoutId);
   } catch (Exception e)
   {
    e.printStackTrace();
   }
  }
 }

通过传入的activity对象,获得它的Class类型,判断是否写了ContentView这个注解,如果写了,读取它的value,然后得到setContentView这个方法,使用invoke进行调用;
有个常量:

private static final String METHOD_SET_CONTENTVIEW = "setContentView";

B、接下来是注入Views

private static final String METHOD_FIND_VIEW_BY_ID = "findViewById";
 /**
  * 注入所有的控件
  *
  * @param activity
  */
 private static void injectViews(Activity activity)
 {
  Class<? extends Activity> clazz = activity.getClass();
  Field[] fields = clazz.getDeclaredFields();
  // 遍历所有成员变量
  for (Field field : fields)
  { 

   ViewInject viewInjectAnnotation = field
     .getAnnotation(ViewInject.class);
   if (viewInjectAnnotation != null)
   {
    int viewId = viewInjectAnnotation.value();
    if (viewId != -1)
    {
     Log.e("TAG", viewId+"");
     // 初始化View
     try
     {
      Method method = clazz.getMethod(METHOD_FIND_VIEW_BY_ID,
        int.class);
      Object resView = method.invoke(activity, viewId);
      field.setAccessible(true);
      field.set(activity, resView);
     } catch (Exception e)
     {
      e.printStackTrace();
     } 

    }
   } 

  } 

 }

获取声明的所有的属性,遍历,找到存在ViewInject注解的属性,或者其value,然后去调用findViewById方法,最后把值设置给field~~~
好了,把这两个方法写到inject里面就好了。

 public static void inject(Activity activity)
 { 

  injectContentView(activity);
  injectViews(activity); 

 }

效果图:

4.View的事件的注入
光有View的注入能行么,我们写View的目的,很多是用来交互的,得可以点击神马的吧。摒弃传统的神马,setOnClickListener,然后实现匿名类或者别的方式神马的,我们改变为:

package com.zhy.zhy_xutils_test; 

import android.view.View;
import android.widget.Button;
import android.widget.Toast; 

import com.zhy.ioc.view.annotation.ContentView;
import com.zhy.ioc.view.annotation.OnClick;
import com.zhy.ioc.view.annotation.ViewInject; 

@ContentView(value = R.layout.activity_main)
public class MainActivity extends BaseActivity
{
 @ViewInject(R.id.id_btn)
 private Button mBtn1;
 @ViewInject(R.id.id_btn02)
 private Button mBtn2; 

 @OnClick({ R.id.id_btn, R.id.id_btn02 })
 public void clickBtnInvoked(View view)
 {
  switch (view.getId())
  {
  case R.id.id_btn:
   Toast.makeText(this, "Inject Btn01 !", Toast.LENGTH_SHORT).show();
   break;
  case R.id.id_btn02:
   Toast.makeText(this, "Inject Btn02 !", Toast.LENGTH_SHORT).show();
   break;
  }
 } 

}

直接通过在Activity中的任何一个方法上,添加注解,完成1个或多个控件的事件的注入。这里我把onCreate搬到了BaseActivity中,里面调用了ViewInjectUtils.inject(this);

(1)注解文件

package com.zhy.ioc.view.annotation; 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 

@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBase
{
 Class<?> listenerType(); 

 String listenerSetter(); 

 String methodName();
} 

package com.zhy.ioc.view.annotation; 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; 

import android.view.View; 

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@EventBase(listenerType = View.OnClickListener.class, listenerSetter = "setOnClickListener", methodName = "onClick")
public @interface OnClick
{
 int[] value();
}

EventBase主要用于给OnClick这类注解上添加注解,毕竟事件很多,并且设置监听器的名称,监听器的类型,调用的方法名都是固定的,对应上面代码的:

代码如下:

listenerType = View.OnClickListener.class, listenerSetter = "setOnClickListener", methodName = "onClick"

Onclick是用于写在Activity的某个方法上的:

 @OnClick({ R.id.id_btn, R.id.id_btn02 })
 public void clickBtnInvoked(View view)

如果你还记得,上篇博客我们的ViewInjectUtils.inject(this);里面已经有了两个方法,本篇多了一个:

public static void inject(Activity activity)
 {
  injectContentView(activity);
  injectViews(activity);
  injectEvents(activity);
 }

(2)injectEvents

/**
  * 注入所有的事件
  *
  * @param activity
  */
 private static void injectEvents(Activity activity)
 { 

  Class<? extends Activity> clazz = activity.getClass();
  Method[] methods = clazz.getMethods();
  //遍历所有的方法
  for (Method method : methods)
  {
   Annotation[] annotations = method.getAnnotations();
   //拿到方法上的所有的注解
   for (Annotation annotation : annotations)
   {
    Class<? extends Annotation> annotationType = annotation
      .annotationType();
    //拿到注解上的注解
    EventBase eventBaseAnnotation = annotationType
      .getAnnotation(EventBase.class);
    //如果设置为EventBase
    if (eventBaseAnnotation != null)
    {
     //取出设置监听器的名称,监听器的类型,调用的方法名
     String listenerSetter = eventBaseAnnotation
       .listenerSetter();
     Class<?> listenerType = eventBaseAnnotation.listenerType();
     String methodName = eventBaseAnnotation.methodName(); 

     try
     {
      //拿到Onclick注解中的value方法
      Method aMethod = annotationType
        .getDeclaredMethod("value");
      //取出所有的viewId
      int[] viewIds = (int[]) aMethod
        .invoke(annotation, null);
      //通过InvocationHandler设置代理
      DynamicHandler handler = new DynamicHandler(activity);
      handler.addMethod(methodName, method);
      Object listener = Proxy.newProxyInstance(
        listenerType.getClassLoader(),
        new Class<?>[] { listenerType }, handler);
      //遍历所有的View,设置事件
      for (int viewId : viewIds)
      {
       View view = activity.findViewById(viewId);
       Method setEventListenerMethod = view.getClass()
         .getMethod(listenerSetter, listenerType);
       setEventListenerMethod.invoke(view, listener);
      } 

     } catch (Exception e)
     {
      e.printStackTrace();
     }
    } 

   }
  } 

 }

嗯,注释尽可能的详细了,主要就是遍历所有的方法,拿到该方法省的OnClick注解,然后再拿到该注解上的EventBase注解,得到事件监听的需要调用的方法名,类型,和需要调用的方法的名称;通过Proxy和InvocationHandler得到监听器的代理对象,显示设置了方法,最后通过反射设置监听器。
这里有个难点,就是关于DynamicHandler和Proxy的出现,如果不理解没事,后面会详细讲解。

(3)DynamicHandler
这里用到了一个类DynamicHandler,就是InvocationHandler的实现类:

package com.zhy.ioc.view; 

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap; 

public class DynamicHandler implements InvocationHandler
{
 private WeakReference<Object> handlerRef;
 private final HashMap<String, Method> methodMap = new HashMap<String, Method>(
   1); 

 public DynamicHandler(Object handler)
 {
  this.handlerRef = new WeakReference<Object>(handler);
 } 

 public void addMethod(String name, Method method)
 {
  methodMap.put(name, method);
 } 

 public Object getHandler()
 {
  return handlerRef.get();
 } 

 public void setHandler(Object handler)
 {
  this.handlerRef = new WeakReference<Object>(handler);
 } 

 @Override
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable
 {
  Object handler = handlerRef.get();
  if (handler != null)
  {
   String methodName = method.getName();
   method = methodMap.get(methodName);
   if (method != null)
   {
    return method.invoke(handler, args);
   }
  }
  return null;
 }
}

好了,代码就这么多,这样我们就实现了,我们事件的注入~~
效果图:

效果图其实没撒好贴的,都一样~~~
(3)关于代理
那么,本文结束了么,没有~~~关于以下几行代码,相信大家肯定有困惑,这几行干了什么?

//通过InvocationHandler设置代理       

DynamicHandler handler = new DynamicHandler(activity);
      handler.addMethod(methodName, method);
      Object listener = Proxy.newProxyInstance(
        listenerType.getClassLoader(),
        new Class<?>[] { listenerType }, handler);

InvocationHandler和Proxy成对出现,相信大家如果对Java比较熟悉,肯定会想到Java的动态代理~~~
关于InvocationHandler和Proxy的文章,大家可以参考:http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/ ps:IBM的技术文章还是相当不错的,毕竟有人审核还有奖金~
但是我们的实现有一定的区别,我为什么说大家疑惑呢,比如反射实现:
mBtn2.setOnClickListener(this);这样的代码,难点在哪呢?
A、mBtn2的获取?so easy
B、调用setOnClickListener ? so easy
but , 这个 this,这个this是OnClickListener的实现类的实例,OnClickListener是个接口~~你的实现类怎么整,听说过反射newInstance对象的,但是你现在是接口!
是吧~现在应该明白上述几行代码做了什么了?实现了接口的一个代理对象,然后在代理类的invoke中,对接口的调用方法进行处理。
(4)代码是最好的老师
光说谁都理解不了,你在这xx什么呢??下面看代码,我们模拟实现这样一个情景:
Main类中实现一个Button,Button有两个方法,一个setOnClickListener和onClick,当调用Button的onClick时,触发的事件是Main类中的click方法
涉及到4个类:
Button

package com.zhy.invocationhandler; 

public class Button
{
 private OnClickListener listener; 

 public void setOnClickLisntener(OnClickListener listener)
 { 

  this.listener = listener;
 } 

 public void click()
 {
  if (listener != null)
  {
   listener.onClick();
  }
 }
}

OnClickListener接口

package com.zhy.invocationhandler; 

public interface OnClickListener
{
 void onClick();
}

OnClickListenerHandler , InvocationHandler的实现类

package com.zhy.invocationhandler; 

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map; 

public class OnClickListenerHandler implements InvocationHandler
{
 private Object targetObject; 

 public OnClickListenerHandler(Object object)
 {
  this.targetObject = object;
 } 

 private Map<String, Method> methods = new HashMap<String, Method>(); 

 public void addMethod(String methodName, Method method)
 {
  methods.put(methodName, method);
 } 

 @Override
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable
 { 

  String methodName = method.getName();
  Method realMethod = methods.get(methodName);
  return realMethod.invoke(targetObject, args);
 } 

}

我们的Main

package com.zhy.invocationhandler; 

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; 

public class Main
{
 private Button button = new Button(); 

 public Main() throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException
 {
  init();
 } 

 public void click()
 {
  System.out.println("Button clicked!");
 } 

 public void init() throws SecurityException,
   NoSuchMethodException, IllegalArgumentException,
   IllegalAccessException, InvocationTargetException
 {
  OnClickListenerHandler h = new OnClickListenerHandler(this);
  Method method = Main.class.getMethod("click", null);
  h.addMethod("onClick", method);
  Object clickProxy = Proxy.newProxyInstance(
    OnClickListener.class.getClassLoader(),
    new Class<?>[] { OnClickListener.class }, h);
  Method clickMethod = button.getClass().getMethod("setOnClickLisntener",
    OnClickListener.class);
  clickMethod.invoke(button, clickProxy); 

 } 

 public static void main(String[] args) throws SecurityException,
   IllegalArgumentException, NoSuchMethodException,
   IllegalAccessException, InvocationTargetException
 { 

  Main main = new Main(); 

  main.button.click();
 } 

}

我们模拟按钮点击:调用main.button.click(),实际执行的却是Main的click方法。
看init中,我们首先初始化了一个OnClickListenerHandler,把Main的当前实例传入,然后拿到Main的click方法,添加到OnClickListenerHandler中的Map中。
然后通过Proxy.newProxyInstance拿到OnClickListener这个接口的一个代理,这样执行这个接口的所有的方法,都会去调用OnClickListenerHandler的invoke方法。
但是呢?OnClickListener毕竟是个接口,也没有方法体~~那咋办呢?这时候就到我们OnClickListenerHandler中的Map中大展伸手了:

@Override
 public Object invoke(Object proxy, Method method, Object[] args)
 throws Throwable
 {
 String methodName = method.getName();
 Method realMethod = methods.get(methodName);
 return realMethod.invoke(targetObject, args);
 }

我们显示的把要执行的方法,通过键值对存到Map里面了,等调用到invoke的时候,其实是通过传入的方法名,得到Map中存储的方法,然后调用我们预设的方法~。
这样,大家应该明白了,其实就是通过Proxy得到接口的一个代理,然后在InvocationHandler中使用一个Map预先设置方法,从而实现Button的onClick,和Main的click关联上。
现在看我们InjectEvents中的代码:

//通过InvocationHandler设置代理
      DynamicHandler handler = new DynamicHandler(activity);
      //往map添加方法
      handler.addMethod(methodName, method);
      Object listener = Proxy.newProxyInstance(
        listenerType.getClassLoader(),
        new Class<?>[] { listenerType }, handler);

是不是和我们init中的类似~~
好了,关于如何把接口的回调和我们Activity里面的方法关联上我们也解释完了~~~

注:部分代码参考了xUtils这个框架,毕竟想很完善的实现一个完整的注入不是一两篇博客就可以搞定,但是核心和骨架已经实现了~~大家有兴趣的可以继续去完善~

(0)

相关推荐

  • 基于Android设计模式之--SDK源码之策略模式的详解

    策略模式其实特别简单(听到这句话,大家是不是心里一下子放松了?).比如排序,官方告诉大家我这里有一个排序的接口ISort的sort()方法,然后民间各尽其能,实现这个排序的方法:冒泡,快速,堆等等.这些方法就是"不同的策略".然后,某个模块下,需要一个排序方法,但是暂时不能指定具体的sort方法(出于扩展的考虑),就需要使用ISort接口了.最后,具体什么场景下,传入什么具体的sort方法,实现灵活的排序.这就是策略模式!下面,我们分析Android中的动画是如何使用策略模式的. 1.

  • Android设计模式系列之组合模式

    Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用.在android UI设计,几乎所有的widget和布局类都依靠这两个类. 组合模式,Composite Pattern,是一个非常巧妙的模式.几乎所有的面向对象系统都应用到了组合模式. 1.意图 将对象View和ViewGroup组合成树形结构以表示"部分-整体"的层次结构(View可以做为ViewGroup的一部分). 组合模式使得用户对单个对象View和组合对象ViewGrou

  • Android开发中的MVC设计模式浅析

    Android开发中的MVC设计模式的理解 1. Android系统中分层的理解: (1).在Android的软件开发工作中,应用程序的开发人员主要是应用Android Application Framework层封装好的Api进行快速开发. (2).在Android框架的四个层次中,下层为上层服务,上层需要下层的支持,上层需要调用下层的服务. (3).这种分层的方式带来极大的稳定性.灵活性和可扩展性,使得不同层的开发人员可以按照规范专心特定层的开发. (4). Android的官方建议应用程序

  • Android设计模式系列之工厂方法模式

    工厂方法模式,往往是设计模式初学者入门的模式,的确,有人称之为最为典型最具启发效果的模式. android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具管理类. 今天以ThreadFactory举例说明一下简单工厂模式和工厂方法模式. 工厂方法模式,Factory Method,简单的方式,不简单的应用. 1.意图 定义一个用于创建对象的接口,让子类决定实例化哪个类.工厂方式模式使一个类的实例化延迟到其子类. 热门词汇:虚构造器 延迟 创建对象

  • Android 单例模式 Singleton 简单实例设计模式解析

    单例模式 Singleton 简单实例设计模式解析 前言 今天我来全面总结一下Android开发中最常用的设计模式 - 单例模式. 关于设计模式的介绍,可以看下我之前写的:1分钟全面了解"设计模式" 目录 1. 引入 1.1 解决的是什么问题 之前说过,设计模式 = 某类特定问题的解决方案,那么单例模式是解决什么问题的解决方案呢? 含义:单例 =一个实例: 解决的问题:降低对象之间的耦合度 解决方法:单例模式,即实现一个类只有一个实例化对象,并提供一个全局访问点 1.2 实例引入 接下

  • Android设计模式之Builder模式详解

    Builder模式使用链式结构创建复杂对象,将过程与结果分开,创建过程中可以自行组合. 使用场景 一个对象,不同组合,不同顺序生成不同的结果 优点:封装性更规范,程序调用不用关系内部细节,注重结果即可 缺点:如果builder对象过多,会加大内存消耗 public class TabInfoBean { private int count;//Tab的个数 必选 private int currentTab;//默认选中的tab 必选 private String[] tabText;//文字必

  • android设计模式之单例模式详解

    这是我们最常见的一类模式,对这一类模式有一个通用的特点就是: 封装创建的方式和过程. 这里所谓封装就是隐藏的意思,对对象的创建方法和过程不可见,或者是虚拟的过程. 隐藏创建方式,就是如单例,工厂方法,隐藏创建过程则是指builder,原型,至于抽象工厂,我认为他包含了以上两种. 我们想想一个对象的创建有哪些步骤? 1.创建什么东西?--接口定义 2.谁创建?        --决策类or帮助类 3.如何创建?     --how,创建过程 4.什么时候创建?    --创建时机的触发 由此可知,

  • Android设计模式之适配器(Adapter)模式

    本文实例为大家分享了Android适配器模式源码,供大家参考,具体内容如下 1. 模式介绍 1.1模式的定义: 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 1.2模式的使用场景: 用电源接口做例子,笔记本电脑的电源一般都是接受5V的电压,但是我们生活中的电线电压一般都是220V的输出.这个时候就出现了不匹配的状况,在软件开发中我们称之为接口不兼容,此时就需要适配器来进行一个接口转换.在软件开发中有一句话正好体现了这点:任

  • Android中的设计模式

    一般来说,常用的设计模式有以下八种:单例.工厂.观察者.代理.命令.适配器.合成.访问者 单例模式:目的是为了让系统中只有一个调用对象,缺点是单例使其他程序过分依赖它,而且不同单例运行在不同进程中,使得维护困难: 工厂模式:生产固定的一些东西,如抽象类,缺点是产品修改麻烦:如喜欢动作片和爱情片的人分别向服务器发出同一个请求,就可以得到他们想看的影片集,相当于不同对象进行同一请求,需求均得到满足. 观察者模式:就是多个对象对一个对象进行监控,如缓存: 代理模式:自己的事交给别人去做,分别返回结果即

  • android开发设计模式之——单例模式详解

    单例模式是设计模式中最常见也最简单的一种设计模式,保证了在程序中只有一个实例存在并且能全局的访问到.比如在Android实际APP 开发中用到的 账号信息对象管理, 数据库对象(SQLiteOpenHelper)等都会用到单例模式.下面针对一些例子分析一下我们在开发过程中应用单例模式需要注意的点.  一.作用 单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点 二.适用场景 1. 应用中某个实例对象需要频繁的被访问. 2. 应用中每次启动只会存在一个实例.如账号

随机推荐