设计模式之【工厂模式】

来源:互联网 发布:盐为什么国家控制知乎 编辑:程序博客网 时间:2024/06/16 08:16

工厂模式概念:

实例化对象,用工厂方法代替new操作;

工厂模式包括工厂方法模式和抽象方法模式;

抽象工厂模式是工厂方法模式的扩展;


工厂模式的意图

定义一个工厂来创建对象,但是让子类来决定哪些类需要被实例化;

工厂方法把实例化的工作推迟到子类中去实现;


什么情况下适合工厂模式?

有一组类似的对象需要创建;

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

系统需要考虑扩展性,不应依赖于产品类实例如何被创建、组合和表达的细节;


项目需求:

在软件系统中经常面临着“对象”的创建工作,由于需求的变化,这个对象肯能随之也会发生变化,但它却拥有比较稳定的接口;

为此我们需要提供一种封装机制来隔离出这个易变对象的变化,从而保持系统中其他依赖该对象的对象不随着需求变化而变化。


解决之道:

1.尽量松耦合,一个对象的依赖对象的变化与本身无关;

2.具体产品与客户端剥离,责任分割;


工厂模式方法类图:



抽象工厂模式类图:



抽象工厂模式举例:现在有一个抽象硬件工厂,下面有多个具体工厂,生产一系列类似的产品族,如图所示:



应用场景举例:

比如现在计算机里面有一个游戏,游戏里面的角色分为男性、女性、儿童,他们分别需要穿戴不同的服饰,那么这个时候我们通过工厂模式来完成获取不同的服饰对象。


首先定义一个服饰接口:

/** * 人物服饰接口 *  * @author bear * */public interface ClothingInterface {/** * 为人物画上服饰 */public abstract void draw();}

然后定义三个服饰类,它们都是ClothingInterface的实现类:

/** * 男性人物的服饰 *  * @author bear * */public class MensWear implements ClothingInterface {/** * 在UI上为男性人物添加上服饰 */@Overridepublic void draw() {// TODO Auto-generated method stubSystem.out.println("**************男装************");}}


/** * 女性人物的服饰 *  * @author bear * */public class WomansWear implements ClothingInterface {/** * 在UI上为女性人物添加上服饰 */@Overridepublic void draw() {// TODO Auto-generated method stubSystem.out.println("**************女装************");}}


/** * 儿童人物的服饰 *  * @author bear * */public class ChildrensWear implements ClothingInterface {/** * 在UI上为儿童人物添加上服饰 */@Overridepublic void draw() {// TODO Auto-generated method stubSystem.out.println("**************童装************");}}


接着,我们这里来定义服饰工厂类:

import java.util.Map;/** * 服饰工厂 *  * @author bear * */public class ClothingFactory {//存储关键词和类的全路径键值对private Map<String, String> classNameMap;//工厂构造方法,在方法中初始化mappublic ClothingFactory(){PropertiesReader pr = new PropertiesReader();classNameMap = pr.getProperties();}/** * 工厂生产方法,根据关键词来生产对象 * 缺点:每次新加入一种类别,都需要在这里增加代码 *  * @param key 传入需要的服饰类别 * @return 返回客户需要的服饰 *//* * public ClothingInterface newInstance(int key){ switch (key) {case Clothing.Men:return new MensWear();case Clothing.Women:return new WomansWear();case Clothing.Children:return new ChildrensWear();default:return null;}}* *//** * 工厂生产方法,根据关键词来索取类名,利用反射来生产对象 *  * @param key * @return */public ClothingInterface newInstance(String key){try {//获取到要实例化的类的全路径String className = classNameMap.get(key);//通过反射的方法来生成新的实例ClothingInterface clothing = (ClothingInterface)Class.forName(className).newInstance();//返回新实例return clothing;} catch (Exception e) {// TODO: handle exceptionreturn null;}} }

在构造方法中,通过读取属性,来初始化map,属性读取类的定义如下:

/** * 属性文件读取类 *  * @author bear * */public class PropertiesReader {/** * 读取属性文件中的键值对到map中,然后返回 *  * @return */public Map<String, String> getProperties(){Properties props = new Properties();Map<String, String> map = new HashMap<String, String>();try {InputStream is = this.getClass().getResourceAsStream("Type.properties");props.load(is);Enumeration en = props.propertyNames();while (en.hasMoreElements()) {String key = (String) en.nextElement();String property = props.getProperty(key);map.put(key, property);}} catch (Exception e) {// TODO: handle exception}return map;}}

这里的属性文件名称叫做Type.properties,它的内容是这样的:

men=com.bear.factorypattern.MensWearwomen=com.bear.factorypattern.WomansWearchildren=com.bear.factorypattern.ChildrensWear

然后我们在Clothing这样的一个实体类中定义几个key的常量值:

/** * 服饰类 *  * @author bear * */public class Clothing {public static final String Men = "men";public static final String Women = "women";public static final String Children = "children";}


最后,我们在客户端的Main方法中,来通过工厂获取到我们需要的实例:

public class UITest {public static void main(String[] args) {ClothingFactory factory = new ClothingFactory();ClothingInterface clothing01 = factory.newInstance(Clothing.Men);clothing01.draw();ClothingInterface clothing02 = factory.newInstance(Clothing.Women);clothing02.draw();ClothingInterface clothing03 = factory.newInstance(Clothing.Children);clothing03.draw();}}


打印结果如下:

**************男装**************************女装**************************童装************

总结:在以上的示例中,如果我们要新添加一种服饰,需要的操作是:

(1).新建服饰类,该类需要实现ClothingInterface接口;

(2).在properties属性文件中增加映射关系;

(3).在Clothing类中添加常量key;


工厂模式示例代码下载链接:

FactoryPatternDemo


抽象工厂模式实际上就是有一个新的接口,那么这个接口中包含了一系列的相关的接口产品簇,抽象工厂专门负责生产产品簇,而非单个产品。


常见工厂模式的应用:

(1).JDBC

是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。



(2)Spring BeanFactory

BeanFactory,作为Spring基础的IOC容器,是Spring的一个Bean工厂。

如果但从工厂模式的角度思考,它就是用来“生产Bean”,然后提供给客户端。

Bean的实例化过程:

a.调用Bean的默认构造方法,或指定的构造方法,生成Bean实例(暂称instance1);

b.如果Bean的配置文件中注入了Bean属性值,则在instance1基础上进行属性注入形成instance2,这种注入是覆盖性的;

c.如果Bean实现了InitializingBean接口,则调用afterPropertiesSet()方法,来改变或操作instance2,得到instance3;

d.如果Bean的配置文件中指定了init-method="init"属性,则会调用指定的初始化方法,则在instance3的基础上调用初始化方法init(),将对象最终初始化为instance4,当然,这个初始化的名字是任意的;



工厂模式的作用:

(1)系统可以在不修改具体工厂角色的情况下引进新的产品;

(2)客户端不必关心对象创建,明确了职责;

(3)更好的理解面向对象的原则是面向接口编程,而不是面向实现编程;


工厂模式的应用场景:

(1)一个系统应当不依赖于产品类实例被创建、组成、表示的细节;

(2)这个系统的产品至少有一个产品簇;

(3)同属于同一产品簇的产品是设计成在一起使用的;

(4)不同的产品以一系列的接口的面貌出现,从而使系统不依赖于接口实现的细节;


0 0
原创粉丝点击