为了程序更好的维护和扩展,在面向对象思维的世界里,首先是面向接口编程,然后我们应该把做什么和怎么做进行分离。

以下我将用一个开晚会的样例来演示一下,终于达到的效果是:工厂+反射+配置文件实现程序的灵活应用。会详细说明一下这个过程是怎么来的,明确了这个,就会对反射和配置文件的结合更加深刻一些。

想要实现的功能是:晚会有一个唱歌、舞蹈、小品的节目单,详细各个节目的表演者仅仅须要一个就能够,每个表演接口都有两个实现类(表演者)。通过client调用不同的实现类来实现不同的节目单。表演者就是“做什么”,那么“怎么做”就是节目单了。首先来看看类图结构:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2xjY29tZW9u/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

以下放代码,首先是接口,即各类表演:

<span style="font-size:14px;">/**跳舞接口*/
</span><pre name="code" class="java">public interface Dancer {

public void dance();} /**小品接口*/public interface Performer { public void performance();}/**歌唱接口*/ public interface Singer { public void sing();}


然后是各个实现类。即表演者:

Dancer接口实现类:
public class YangLiPing implements Dancer { @Override
public void dance() {
System.out.println("杨丽萍跳舞:孔雀舞");
} } public class XiaoHuDui implements Dancer { @Override
public void dance() {
System.out.println("小虎队跳舞:霹雳舞");
} }
Performer接口实现类:
public class GongHanLin implements Performer { @Override
public void performance() {
System.out.println("巩汉林表演:功夫令");
} }
public class ZhaoBenShan implements Performer { @Override
public void performance() {
System.out.println("赵本山表演:卖拐");
} }
Singer接口实现类:
public class ZhouHuaJian implements Singer { @Override
public void sing() {
System.out.println("周华健演唱:刀剑如梦");
} }
public class WangFei implements Singer { @Override
public void sing() {
System.out.println("王菲演唱:我愿意");
} }

client调用方式:

<span style="font-size:14px;"> public static void main(String[] args) {

      //定义晚会流程
//演出:歌曲、舞蹈、表演
//第1种方法:单纯使用多态 System.out.println("晚会開始=======>>"); Singer singer = new ZhouHuaJian();
singer.sing(); Performer performer = new ZhaoBenShan();
performer.performance(); Dancer dancer = new YangLiPing();
dancer.dance(); System.out.println("<<========晚会结束");
}</span>

代码挺简单,只是发现一个问题。作为节目组织者,在现实中基本上是不应该直接与表演者打交道的,而是与其所在的公司或者代理人进行交流,如果如今全部的表演者都同属于一个娱乐公司,那么我仅仅须要从这个娱乐公司里获得我想要的那些表演者就能够了,那么UML图将会变为例如以下结构(Factory就代表这个娱乐公司):

Facotry代码:

public classFactory {

   //提供准备歌手方法
public static Singer getSinger(){
return new ZhouHuaJian();
} //提供准备舞蹈方法
public static Dancer getDancer(){
return new YangLiPing();
} //提供准备表演方法
public static PerformergetPerformer(){
return new GongHanLin();
}
}

那么client代码就变成了这样:

public staticvoidmain(String[] args) {
//定义晚会流程
//演出:歌曲、小品、舞蹈
//第1种方法:使用工厂获取各个表演种类 System.out.println("晚会開始=======>>"); Singersinger = Factory.getSinger();
singer.sing(); Performerperformer = Factory.getPerformer();
performer.performance(); Dancerdancer = Factory.getDancer();
dancer.dance(); System.out.println("<<========晚会结束");
}

大家能够看到,在Factory代码中我们发现还是将各个实现类写死了,也就是说娱乐公司强制某些表演者必须參加,但实际上非常多时候有些表演者可能没法參加,而另外一些闲着的表演者则能够參加。那么我是不是应该在须要表演者的时候动态获取有空參加更好一些呢?这个时候就须要用上配置文件+反射了。

Factory代码更改例如以下:

<span style="font-size:14px;">public class Factory {

   /**提供准备歌手方法*/
public static Singer getSinger(){ //读取配置文件及获取key相应的value
StringclassName = ResourceBundle.getBundle("party").getString("Singer");
Singersinger = null; try {
//将配置文件里读取的完整类名通过反射获取该类的实例
singer= (Singer)Class.forName(className).newInstance();
}catch(InstantiationException | IllegalAccessException
|ClassNotFoundException e) {
e.printStackTrace();
} return singer; } /**提供准备舞蹈方法*/
public static Dancer getDancer(){ StringclassName = ResourceBundle.getBundle("party").getString("Dancer");
Dancerdancer = null; try {
dancer= (Dancer)Class.forName(className).newInstance();
}catch(InstantiationException | IllegalAccessException
|ClassNotFoundException e) {
e.printStackTrace();
} return dancer;
} /**提供准备表演方法*/
public static PerformergetPerformer(){ StringclassName = ResourceBundle.getBundle("party").getString("Performer");
Performerperformer = null; try {
performer= (Performer)Class.forName(className).newInstance();
}catch(InstantiationException | IllegalAccessException
|ClassNotFoundException e) {
e.printStackTrace();
} return performer;
}
}</span>

配置文件party.properties中的代码:

Singer = com.lc.reflect.demo3.person.WangFei
Performer = com.lc.reflect.demo3.person.ZhaoBenShan
Dancer =com.lc.reflect.demo3.person.XiaoHuDui

这样就能把代码解耦了。

细致看的话,在Factory中的代码3个方法基本上没啥不同,除了变量和对象不同。发现了代码的坏味道。那就重构吧:

public classFactory1 {     

      /**提供准备歌手方法*/
public static Singer getSinger(){ Singersinger = null;
return (Singer)getObject("Singer",singer);
} /**提供准备舞蹈方法*/
public static Dancer getDancer(){ Dancerdancer = null; return (Dancer)getObject("Dancer",dancer);
} /**提供准备表演方法*/
public static PerformergetPerformer(){ Performerperformer = null; return (Performer)getObject("Performer",performer);
} /**
* 获取目标对象的方法
* @param objName 对象名称
* @param obj 对象类型
* @return对象
*/
public static Object getObject(StringobjName,Object obj){ //获取配置文件里的目标对象路径
StringclassName = ResourceBundle.getBundle("party").getString(objName);
try {
//获取目标对象实例
obj= Class.forName(className).newInstance();
}catch(InstantiationException | IllegalAccessException
|ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}

这样就简洁多了。

学习一块知识不只要学习API是怎么用的,还要与生活相结合,做出一个个简单有效的Demo,同一时候在做Demo的过程中,假设发现了编写的代码有值得重构的地方,一定不要停下思考的脚步,Just do it!尽管对反射的详细实现原理和过程还不太清楚,但首先会用才干有继续研究的动力。继续努力中~~


Java反射-简单应用的更多相关文章

  1. Java反射+简单工厂模式总结

    除了 new 之外的创建对象的方法 通过 new 创建对象,会使得程序面向实现编程,先举个例子,某个果园里现在有两种水果,一种是苹果,一种是香蕉,有客户想采摘园子里的水果,要求用get()方法表示即可 ...

  2. Java反射 - 简单的给Bean赋值和取值

    由于项目的实际需要,所以利用java反射原理写了一个简单给bean赋值和取值通用的类,在此记录下方便自己日后用到,也为需要的兄弟提供个参考例子. 工具类BeanRefUtil:   package c ...

  3. Java反射简单使用--第一次细致阅读底层代码

    1:所写的东西都经过验证,保证正确,环境jdk8,eclipse2:在例子中,尽量以生产环境中实际代码为例,那种固定值什么的没什么意义 问题: 1:想获取调用方法所需要的参数 2:参数是以json形式 ...

  4. Java 反射(简单捋一下)

    有Student类,Person类,还有一个叫Class的类,这是反射的源头. 正常方式:通过完整的类名 > 通过new实例化 > 取得实例化对象 反射方式:实例化对象 > getC ...

  5. java反射简单实例

    这篇博友的总结的反射知识点是比较全面的 http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html 下面介绍我用反射做的两个功能 ...

  6. java反射机制简单实例

    目录 Java反射 简单实例 @(目录) Java反射 Java语言允许通过程序化的方式间接对Class进行操作.Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通 ...

  7. java反射机制的简单介绍

    参考博客: https://blog.csdn.net/mlc1218559742/article/details/52754310 先给出反射机制中常用的几个方法: Class.forName (& ...

  8. java反射并不是什么高深技术,面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象

    java反射并不是什么高深技术,面向对象语言都有这个功能. 面向对象语言都有这个功能,而且功能也很简单,就是利用jvm动态加载时生成的class对象,去获取类相关的信息 2.利用java反射可以调用类 ...

  9. Java反射(六)纯面向接口编程的简单框架实践

    我们知道在使用MyBatis开发时,只需要添加DAO接口和对应的映射XML文件,不需要写DAO的实现类,其实底层是通过动态代理实现. 本文将使用前几篇文章的知识点实现一个纯面向接口编程的简单框架,与M ...

随机推荐

  1. VS2015中使用Git

    10分钟学会在VS2015中使用Git 写程序必然需要版本控制,哪怕是个人项目也是必须的.我们在开发UWP APP的时候,VS2015默认提供了对微软TFS和Git的支持.考虑到现在Git很火,作为微 ...

  2. 算法分析-堆排序 HeapSort 优先级队列

    堆排序的是集合了插入排序的单数组操作,又有归并排序的时间复杂度,完美的结合了2者的优点. 堆的定义 n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆. 情形1:ki < ...

  3. UML-类图,包图

    UML构造设计模型   一.类图  二.包图   三.组件图   四.部署图   一.类图     1.类:类由三格表示:类名,类的属性,类的操作              类名: 首字母大学     ...

  4. PSAM SAM

    第一个问题: 为什么要用SAM? 究竟谁最开始使用SAM这个词,已经无从考证,能够确认的是:这个世界上先有了PSAM,然后才有了SAM.由于网络状况的原因,或者是应用环境的要求,使用IC卡作为支付介质 ...

  5. C++流操作之fstream

    在Windows平台对文件进行存取操作可选的方案有很多,如果采用纯C,则需要用到File*等,当然也可以直接调用Windows API来做:如果采用C++,首先想到的就是文件流fstream.虽然在C ...

  6. SQL分类取每一类第一项

    实际应用中经常会碰到这样的需求,在给定的数据集中要求返回每一类型中最大的一条,抑或是最小的一条,抑或是按时间排序最近的一条等等.很多人面对这样的需求显得束手无策,其实这个需求实现有很多种方法,今天给大 ...

  7. setInterval和setTimeout的使用区别

    setTimeout和setInterval的使用 这两个方法都可以用来实现在一个固定时间段之后去执行JavaScript.不过两者各有各的应用场景. 方 法 实际上,setTimeout和setIn ...

  8. mysql 基本使用

    SQL分类 -------------------数据库------------ 创建数据库  create database xxx; 查询所有的数据库 show databases; 查询当前数据 ...

  9. MJExtension

    MJExtension 长话短说下面我们通过一个列子来看下怎么使用 1. 先把框架拉进去你的项目 2. 首先我这次用到的json最外层是一个字典,根据数据的模型我们可以把这个归类为字典中有数组,数组中 ...

  10. JAVA 可视化分析工具 第12节

    JAVA 可视化分析工具  第12节 经过前几章对堆内存以及垃圾收集机制的学习,相信小伙伴们已经建立了一套比较完整的理论体系!那么这章我们就根据已有的理论知识,通过可视化工具来实践一番. 我们今天要讲 ...