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

工厂模式

简介

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

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

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

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

分类

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

  • 简单工厂模式(Simple Factory)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)

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

使用情况

  • 在编码时不能预见需要创建哪种类的实例
  • 系统不应依赖于产品类实例如何被创建,组合和表达的细节。

工厂方法模式组成

  1. 抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
  2. 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
  3. 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
  4. 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
  5. 客户端:调用工厂类去产生实例,并调用这些实例的方法进行相应的工作。

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

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

当你在玩最近流行的游戏,英雄联盟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反射机制demo(七)—反射机制与工厂模式的更多相关文章

  1. JAVA设计模式(01):创建型-工厂模式【工厂方法模式】(Factory Method)

    简单工厂模式尽管简单,但存在一个非常严重的问题.当系统中须要引入新产品时,因为静态工厂方法通过所传入參数的不同来创建不同的产品,这必然要改动工厂类的源码,将违背"开闭原则".怎样实 ...

  2. Java编程思想:利用内部类实现的工厂模式

    public class Test { public static void main(String[] args) { Factories.test(); } } /* 设计模式之禅中的工厂模式是这 ...

  3. JAVA设计模式 3【创建型】理解工厂模式与抽象工厂模式

    上一节我们已经学习了原型模式,稍微复习一下:通过重写Object 类的clone() 方法实现浅克隆,浅克隆也要实现Cloneable 标记接口.而深克隆则是将对象通过序列化和反序列化 的方式进行创建 ...

  4. JAVA笔记7__接口应用/Object类/简单工厂模式/静态代理模式/适配器模式

    /** * 接口应用 */ public class Main { public static void main(String[] args) { Person p = new Person(&qu ...

  5. IOC的实现原理—反射与工厂模式的结合

    反射机制概念   我们考虑一个场景,如果我们在程序运行时,一个对象想要检视自己所拥有的成员属性,该如何操作?再考虑另一个场景,如果我们想要在运行期获得某个类的Class信息如它的属性.构造方法.一般方 ...

  6. C#回顾 - 7.如何使用反射实现工厂模式?

    工厂模式是一种比较常用的设计模式,其基本思想在于使用不同的工厂类型来打造不同产品的部件.例如,我们在打造一间屋子时,可能需要窗户.屋顶.门.房梁.柱子等零部件.有的屋子需要很多根柱子,而有的屋子又不需 ...

  7. 重学 Java 设计模式:实战抽象工厂模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  8. Java实验项目三——简单工厂模式

    Program: 请采用采用简单工厂设计模式,为某个汽车销售店设计汽车销售系统,接口car至少有方法print(), 三个汽车类:宝马.奥迪.大众 (属性:品牌,价格),在测试类中根据客户要求购买的汽 ...

  9. Java设计模式(一) 简单工厂模式不简单

    摘要:本文介绍了简单工厂模式的概念,优缺点,实现方式,以及结合Annotation和反射的改良方案(让简单工厂模式不简单).同时介绍了简单工厂模式(未)遵循的OOP原则.最后给出了简单工厂模式在JDB ...

  10. Java 抽象工厂模式

    抽象工厂模式(Abstract Factory Pattern)是工厂方法模式的进一步抽象,其英文原话"Provide an interface for creating families ...

随机推荐

  1. Windows Server环境下消息队列之ActiveMQ实战

    环境准备 1.安装jdk1.7+ 2.下载新版ActiveMQ http://activemq.apache.org/ 3.启动activemq服务 4.启动成功后的界面是  5.启动成功后 浏览器访 ...

  2. 训练赛第二场G题 ZOJ 2343

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2343 解题报告:首先我假设最后的正确的结果是a[1] , a[2 ...

  3. G - Pandaland HDU - 6005 (找最小环)

    题目链接:https://cn.vjudge.net/contest/275153#problem/G 具体思路: 我们可以按照暴力的方法进行做 , 我们可以枚举每一条边,将这条边的权值设置为inf, ...

  4. 20165230 《Java程序设计》实验一(Java开发环境的熟悉)实验报告

    20165230 <Java程序设计>实验一(Java开发环境的熟悉)实验报告 一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:田坤烨 学号:20165230 成绩: 指 ...

  5. CentOS配置163yum源

    1.下载repo文件 wget http://mirrors.163.com/.help/CentOS6-Base-163.repo 2.备份并替换系统的repo文件 [root@localhost ...

  6. 【驱动】USB驱动·入门【转】

    转自:http://www.cnblogs.com/lcw/p/3159371.html Preface USB是目前最流行的系统总线之一.随着计算机周围硬件的不断扩展,各种设备使用不同的总线接口,导 ...

  7. 一步一步搭建oracle 11gR2 rac+dg之共享磁盘设置(三)【转】

    一步一步在RHEL6.5+VMware Workstation 10上搭建 oracle 11gR2 rac + dg 之共享磁盘准备 (三) 注意:这一步是配置rac的过程中非常重要的一步,很多童鞋 ...

  8. Python之协程(coroutine)

    Python之协程(coroutine) 标签(空格分隔): Python进阶 coroutine和generator的区别 generator是数据的产生者.即它pull data 通过 itera ...

  9. Linux 多线程编程—使用条件变量实现循环打印

    编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示:如:ABCABC….依次递推. 使用条件变量来实现: #inc ...

  10. Vue模板语法总结

    文本 数据绑定最常见的方式就是使用"Mustache"语法(两个大括号{{ }})的文本插值 <span>Message: {{ msg }}</span> ...