一、依赖注入(DI) 控制反转(IOC)
先看上面三张图使用的公共组件ToggleBar,这个组件要求左按钮和右按钮点击的时候,显示的内容会向左或向右缓动,隐藏掉一部分,并显示之前遮住的一部分。如图所示,不同的应用场景,每一个小格子内容是不同的,有的是一个按钮,有的是一个物品图标,有的复杂些,还有文本,我们简称为renderA,renderB,renderC。这些变化的部分,作为ToggleBar的设计者,是不可预知的,可知的只有点击左右按钮,它们会排成一行做缓动。那么,我们应该怎么设计才能方便使用者呢?
毫无疑问,ToggleBar中必须有一个对象保存着这些变化的内容用来展示,就叫render吧。它的类型可以是renderA,renderB,renderC的基类,当然是一个接口更方便,把它们共有的逻辑再抽象到基类里。这样ToggleBar就要求使用它的时候,必须指明一个render接口的对象,否则它不知道怎么去显示。
第二个问题就是怎么把这个Render传进去,最好是在构造方法里要求传入,因为构造方法里需要执行UI初始化。也可以使用setRender方法重置。
总结:ToggleBar依赖render才能正常工作,但render的构造却不受它控制,它把控制权交给了具体的使用者,这就是控制反转。render通过构造方法传入,这个就叫依赖注入。
以下参考轻松理解 Java开发中的依赖注入(DI)和控制反转(IOC)
对比以下的两个简单程序:
简单java程序
package demo;
public class Activity {
public Activity(){
this.onCreate();
}
public void onCreate(){
System.out.println("onCreate called");
}
public void sayHi(){
System.out.println("Hello world!");
}
public static void main(String[] args) {
Activity a = new Activity();
a.sayHi();
}
}
简单Android程序
package demo;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.append("Hello ");
tv.append("world!");
setContentView(tv);
}
}
这两个程序最大的区别就是,前者程序的运行完全由开发控制,后者程序的运行由Android框架控制.两个程序都有个onCreate方法.前者程序中,如果开发者觉得onCreate 名称不合适,想改为Init,没问题,直接就可以改, 相比下,后者的onCreate 名称就不能修改.因为,后者使用了框架,享受框架带来福利的同时,就要遵循框架的规则.
这就是控制反转.可以说, 控制反转是所有框架最基本的特征.也是框架和普通类库最大的不同点.
很多Android开发工程师在享用控制反转带来的便利,去不知什么是控制反转.就有点像深海里的鱼不知到什么是海水一样.
通过框架可以把许多共用的逻辑放到框架里,让用户专注自己程序的逻辑.这也是为什么现在,无论手机开发,网页开发,还是桌面程序, 也不管是Java,PHP,还是Python框架无处不在.
二、反射
通过字符串获取类,动态生成对象。可以使用XML文件来组织这些字符串。反射主要是升级了工厂模式。
参考
Java反射入门
Java基础与提高干货系列——Java反射机制
以下参考Java反射机制的适用场景及其利与弊
- Java的反射机制在做基础框架的时候非常有用,有一句话这么说来着:反射机制是很多Java框架的基石。而一般应用层面很少用,不过这种东西,现在很多开源框架基本都已经给你封装好了,自己基本用不着写。典型的除了hibernate之外,还有spring也用到很多反射机制。经典的就是在xml文件或者properties里面写好了配置,然后在Java类里面解析xml或properties里面的内容,得到一个字符串,然后用反射机制,根据这个字符串获得某个类的Class实例,这样就可以动态配置一些东西,不用每一次都要在代码里面去new或者做其他的事情,以后要改的话直接改配置文件,代码维护起来就很方便了,同时有时候要适应某些需求,Java类里面不一定能直接调用另外的方法,这时候也可以通过反射机制来实现。
总的来说,自己写的很少,具体什么时候要用那要看需求,反射机制无非就是根据一个String来得到你要的实体对象,然后调用它原来的东西。但是如果是要自己写框架的话,那就会用得比较多了。 - 当你做一个软件可以安装插件的功能,你连插件的类型名称都不知道,你怎么实例化这个对象呢?因为程序是支持插件的(第三方的),在开发的时候并不知道 。所以无法在代码中 New出来 ,但反射可以,通过反射,动态加载程序集,然后读出类,检查标记之后再实例化对象,就可以获得正确的类实例。
- 在编码阶段不知道那个类名,要在运行期从配置文件读取类名, 这时候就没有办法硬编码new ClassName(),而必须用到反射才能创建这个对象.反射的目的就是为了扩展未知的应用。比如你写了一个程序,这个程序定义了一些接口,只要实现了这些接口的dll都可以作为插件来插入到这个程序中。那么怎么实现呢?就可以通过反射来实现。就是把dll加载进内存,然后通过反射的方式来调用dll中的方法。很多工厂模式就是使用的反射。
三、AOP
参考JavaWeb过滤器.监听器.拦截器-原理&区别-个人总结
面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?**这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。 **一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。如果加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来说,AOP基本上是通过代理机制实现的。AOP在编程历史上可以说是里程碑式的,对OOP编程是一种十分有益的补充。