Java反射机制demo(七)—反射机制与工厂模式

工厂模式

简介

工厂模式是最常用的实例化对象模式。

工厂模式的主要作用就是使用工厂方法代替new操作。

为什么要使用工厂模式?直接new不好吗?

直接new没有什么不好,只是工厂模式可以给系统带来更好的可扩展性和尽量少的修改量。

分类

工厂模式一般有两类,一类是工厂方法模式,另一类是抽象工厂模式。但是《head first 设计模式》中,通过某些例子,实际上把工厂模式分为三种:

简单工厂模式(Simple Factory)

工厂方法模式(Factory Method)

抽象工厂模式(Abstract Factory)

其中简单工厂模式是工厂方法模式的一种特例。

使用情况

在编码时不能预见需要创建哪种类的实例

系统不应依赖于产品类实例如何被创建,组合和表达的细节。

工厂方法模式组成

抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。

抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

客户端:调用工厂类去产生实例,并调用这些实例的方法进行相应的工作。

简单工厂模式实际上是一种静态的工厂方法模式。简单工厂模式由一个工厂类根据传入的参数决定创建哪一种的产品类。

现在先给出一个没有使用反射机制的工厂模式。

当你在玩最近流行的游戏,英雄联盟LOL或者是DOTA/DOTA2,你和队友包括敌方阵营都会选择英雄。这个英雄的选择过程我们可以看做是一个new一个英雄。例如我要选择(new)一个暗夜刺客,然后我就得到了一个暗夜刺客的实例,接着通过这个实例进行游戏。下面的例子,用简单工厂模式来生产英雄模拟以上过程。

简单工厂模式DEMO:

首先,完成一个英雄的接口,这对应了product接口,即抽象的产品类。

package com.aaron.reflect.factory;

public interface Hero {

public void say();

}

然后用几个不同的类去实现这个接口,这些类就是实际上产品的生产者。

package com.aaron.reflect.factory;

public class EarthShaker implements Hero {

@Override

public void say() {

System.out.println("撼地神牛:Do not push me or I will impale you on my horns.");

}

}

//------------------------分割线------------------------

package com.aaron.reflect.factory;

public class NeverMore implements Hero {

@Override

public void say() {

System.out.println("影魔:What, mortal?");

}

}

然后,我们实现一个静态的工厂方法,在这个工厂类中,静态地得到产品的实例

package com.aaron.reflect.factory;

public class HeroesFactory {

public static Hero choose(String shortName){

Hero hero = null;

if(shortName.equals("ES")){

hero = new EarthShaker();

} else if(shortName.equals("SF")) {

hero = new NeverMore();

}

return hero;

}

}

测试一下:

package com.aaron.reflect.factory;

public class FactoryTest {

public static void main(String[] args) {

HeroesFactory.choose("ES").say();

HeroesFactory.choose("SF").say();

}

}

运行结果:

撼地神牛:Do not push me or I will impale you on my horns.

影魔:What, mortal?

OK,一个简单完整的简单工厂模式就实现了。

工厂方法模式只是把这里的工厂类再次抽象,抽象出一个工厂接口,当使用ES的时候就新建一个ESFactory的实现,使用SF时,就新建一个SFFactory。这样看似麻烦,但是当业务复杂时却能保证频繁的变更不会导致系统越对越乱,只需要添加一个产品,添加一个用来生产产品的工厂。

使用反射机制修改工厂模式

然而,这种更改仍然要耗费很多精力,除了接口其余的我们都更改了。

如上面的简单工厂模式中,如果我们要新增一个英雄,屠夫,Pudge。我们需要做如下更改:

新增Pudge类

修改Factory类,增加Pudge的匹配

新增Pudge代码:

package com.aaron.reflect.factory;

public class Pudge implements Hero {

@Override

public void say() {

System.out.println("屠夫:Ah! Fresh meat!");

}

}

增加Pudge匹配的代码

package com.aaron.reflect.factory;

public class HeroesFactory {

public static Hero choose(String shortName){

Hero hero = null;

if(shortName.equals("ES")){

hero = new EarthShaker();

} else if(shortName.equals("SF")) {

hero = new NeverMore();

} else if (shortName.equals("TF")) {

hero = new Pudge();

}

return hero;

}

}

此时,如果我们把一百多个英雄都添加进去,我们就会修改一百多次工厂类。

现在我们可以使用反射机制,来避免这种麻烦。

使用反射机制改写工厂类:

package com.aaron.reflect.factory;

public class HeroesFactory {

public static Hero choose(String shortName){

Hero hero = null;

try {

hero = (Hero) Class.forName(shortName).newInstance();

} catch (Exception e) {

e.printStackTrace();

}

return hero;

}

}

代码写到这里,问题就来了。

Class.forName(String str)这个方法的参数必须是包含报名的,例如我想得到一个ES撼地神牛,我仅仅传入“ES”必然不行,传入“EarthShaker”这个类名也找不到对应的类,只有传入完整的包名和类名,"com.aaron.reflect.factory.HeroesFactory"。

怎么来解决呢?其中一个办法是引入properties配置文件。

先看一下properties文件;

ES=EarthShaker

SF=NeverMore

TF=Pudge

修改工厂类:

package com.aaron.reflect.factory;

import java.io.FileInputStream;

import java.util.Properties;

public class HeroesFactory {

public static Hero choose(String shortName) {

Hero hero = null;

// 从properties文件中读取shortName对应的完整包名

Properties properties = new Properties();

try {

properties.load(new FileInputStream("src/nameMapping.properties"));

String fullName = properties.getProperty(shortName);

hero = (Hero) Class.forName(fullName).newInstance();

} catch (Exception e) {

e.printStackTrace();

}

return hero;

}

}

这么做就一劳永逸了。

当新增一个产品类时,工厂类就不需要做任何改动了。

但是,程序写到这,应该想到一个很严重的问题,如果工厂类被频繁调用时,没新建一个产品,就要读一次propert ies文件,尽管java对properties的支持非常便捷,但是这么频繁地去操作IO明显在性能上有很大的弱点。

在测试类中,加入计时,得到运行结果如下:

撼地神牛:Do not push me or I will impale you on my horns.

影魔:What, mortal?

屠夫:Ah! Fresh meat!

耗时:6ms

平均耗时5毫秒左右。

这样的话,我们对程序做以下改动。

package com.aaron.reflect.factory;

import java.io.FileInputStream;

import java.io.IOException;

import java.util.Properties;

public class HeroesFactory {

public static Properties init() {

// 从properties文件中读取shortName对应的完整包名

Properties properties = new Properties();

try {

properties.load(new FileInputStream("src/nameMapping.properties"));

} catch (IOException e) {

e.printStackTrace();

}

return properties;

}

public static Hero choose(String shortName) {

Hero hero = null;

try {

String fullName = HeroesFactory.init().getProperty(shortName);

hero = (Hero) Class.forName(fullName).newInstance();

} catch (Exception e) {

e.printStackTrace();

}

return hero;

}

}

然后看一下运行结果:

撼地神牛:Do not push me or I will impale you on my horns.

影魔:What, mortal?

屠夫:Ah! Fresh meat!

耗时:3ms

平均3ms左右。当然这跟机器的性能也有些关系。当然,大部分的耗时应该还是花在了I/O读文件和打印输出上。

抛出这些技术细节问题,

总之,反射机制给工厂模式带来了新的体验。

java 反射 工厂模式_Java反射机制demo(七)—反射机制与工厂模式相关推荐

  1. java注解和反射原理_Java中的注解和反射

    最近又回顾了一下 Java 中的注解和反射知识点,注解在日常开发中使用很多,但是反射比较少.值得注意的是 Java 的各种框架底层源码中大量使用了注解和反射,阅读源码,这些是基本功,面试中这部分内容也 ...

  2. java 反射与泛型_Java基础系列 - 泛型和反射机制

    package com.test5; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Java泛型和反射机 ...

  3. java 父类转子类_Java多态,对象转型,和简单工厂模式。希望对您有帮助!

    各位读者老爷们大家好鸭~图图又来了,今天我们要说一下"多态". 怎么理解这两个字呢?可以理解为同一个引用对象的不同表现形态,即将父类的引用指向子类的对象.这是比较官方的书面解释,大 ...

  4. java中mvc事务_java核心技术第五篇之事务和MVC模式

    第一部分:事务 1.事务的简介: 1.1 在一组操作中(比如增加操作,修改操作),只有增加和修改操作都成功之后,这两个操作才能真正的成功. ,如果这两个操作中,有一个失败了,这两个操作都失败了. 1. ...

  5. java中策略设计模式_Java中的设计模式(五):策略模式

    策略设计模式是行为设计模式之一.当我们为特定任务使用多个算法时,使用策略模式,客户端决定在运行时使用的实际实现. 策略模式的最佳示例之一是Collections.sort()采用Comparator参 ...

  6. java 类加载 双亲委派_Java类加载器和双亲委派机制

    前言 之前详细介绍了Java类的整个加载过程(类加载机制详解).虽然,篇幅较长,但是也不要被内容吓到了,其实每个阶段都可以用一句话来概括. 1)加载:查找并加载类的二进制字节流数据. 2)验证:保证被 ...

  7. java 打印预览_java打印和打印预览机制实例代码

    代码如下: import java.awt.basicstroke; import java.awt.borderlayout; import java.awt.color; import java. ...

  8. java国际化韩文_java国际化介绍+Demo

    引言 今天小编听到了一个词:国际化.现在全球都要多元化了,所以程序国际化也是顺势而出的--(ps:其实这个早就有了,小编也是硬扯到一起的!) 国际化简介 国际化的英文为Internationaliza ...

  9. java虚拟机可以处理_Java虚拟机对类加载的处理机制

    类被加载到虚拟机内存开始,到卸载出内存为止,经历了:加载->验证->准备->解析->初始化->使用->卸载 这七个过程 加载 在加载阶段,虚拟机要完成三件事: (1 ...

  10. java回调与异步_Java同步异步玩转回调机制

    北京这周终于凉快了不少,舒了一口气,但是中暑带来的后遗症还没减轻,晕晕乎乎地上了一周的班也不见好转,基本就是这状态: 程序员 好了,不扯了.上篇文章讲了回调的基本原理:调用方通过方法将自己身的实例传给 ...

最新文章

  1. 计算机网络 关于网速,关于电脑网速慢的说明
  2. vivo 互联网业务就近路由技术实战
  3. 【 C 】初识函数指针
  4. 样式处理——提取样式文件
  5. puppet全方位学习之总结
  6. C++Primer再学习(3)
  7. [原创] ASP.NET 应用程序中使用定时器
  8. hadoop 3.x 关闭安全模式
  9. Android:JNI调用C++自定义类的详细方法
  10. 2017公共DNS服务器评估报告——公共DNS推荐(摘录)
  11. 基于SpringBoot+JSoup+POI+Swagger2实现校园教务系统成绩课程等信息抓取,并提供接口访问的小项目
  12. 寻找http://localhost/phpmyadmin出现的问题:HTTP 错误 404.0 - Not Found 您要找的资源已被删除、已更名或暂时不可用
  13. 杂谈 跟编程无关的事情11
  14. html字体根据宽度自动调整,css – 根据div大小调整字体大小
  15. use SWR为什么能成为我的最爱React库?
  16. 1.2.1数据,数据元素,数据项和数据对象
  17. 【迅为iMX6Q】开发板:迅为官方提供好的kernel的编译
  18. FormData的用途
  19. 给button按钮绑定Enter回车键
  20. C语言红外模块程序,C语言写的红外遥控解码程序

热门文章

  1. 饿了么UI时间选择器
  2. 转型产品经理需要考NPDP吗?
  3. 共享汽车租赁运营管理--解决方案
  4. 投SCI回复审稿人及编辑部的意见
  5. 支付宝与微信新年红包战之我见
  6. POJ 2993 Emag eht htiw Em Pleh
  7. l7sa008b故障代码_韩国麦克比恩电机-L7S 中文说明书 ver1.9.pdf
  8. Python爬虫(前言):有趣的一个爬虫实例(爬取段子,笑话,情感句子)
  9. python关闭excel文件_利用Python读取和修改Excel文件(包括xls文件和xlsx文件)
  10. 学习access的同学们的福利,推荐优秀的access教程