工厂模式(工厂方法模式,抽象工厂模式) Java
来源:互联网 发布:网络打印机怎么添加 编辑:程序博客网 时间:2024/06/10 04:33
工厂模式分为3类:
* 简单工厂模式 Simple Factory
* 工厂方法模式 Factory Method
* 抽象工厂模式 Abstract Factory
thinking in Java 中工厂方法模式的例子:
interface Service{ void method1(); void method2();}interface ServiceFactory{ Service getService();}class Implementation1 implements Service{ Implementation1() {} public void method1(){System.out.println("implementation1 method1");}; public void method2(){System.out.println("implementation1 method2");}; }class Implementation1Factory implements ServiceFactory{ public Service getService(){ return new Implementation1(); }}class Implementation2 implements Service{ Implementation2(){}; public void method1(){System.out.println("implementation2 method1");}; public void method2(){System.out.println("implementation2 method2");};} class Implememntation2Factory implements ServiceFactory{ public Service getService(){ return new Implementation2(); }}public class Factories { public static void serviceConsumer(ServiceFactory fact){ Service s = fact.getService(); s.method1(); s.method2(); } public static void main(String[] args){ serviceConsumer(new Implementation1Factory()); serviceConsumer(new Implememntation2Factory()); }}
知乎上的一个问题
为什么在最后Factories中的静态方法serviceConsumer中,不直接用Service呢?
省掉工厂方法也可以实现多态,直接用Service实例作为参数,向上转型成Service接口,去耦合。
如:
interface Service{ void method1(); void method2();}public static void serviceConsumer(Service s){ s.method1(); s.method2();}
工厂模式真正的精髓并不在于多态去耦合,而是在于“工厂模式”,在Design Pattern中,工厂方法模式是和“虚拟工厂模式”,“生成器模式”,“单例模式”在一起,同属于创建型模式。
创建型模型最大的共同特征就是,把类型的定义过程和实例化过程分离开。即在类自身构造器之外,附加一个经常被误认为没什么用的工厂类,如Thinking in Java里的ServiceFactory:
class ServiceA{ void method1(){}; void method2(){}; // 构造器 ServiceA(){};}class ServiceFactory{ Service getService(){};}
实际中,工厂类作用巨大。
当一个类有很多不同的变种时,就需要工厂类来隔离实例化过程。
class ServiceFactory{ Service getService(){ if(a){ ServiceA sA = new ServiceA(); }else(b){ ServiceB sB = new ServiceB(); }else(c){ ServiceC sC = new ServiceC(); } }}
这确实有用,但实际生活中,这并不是逼迫我们决定分离出工厂类的最主要的原因。真正的原因是:相比于继承,我们更优先使用组合。
真正迫使我们决定分离出工厂类的原因,是实体类使用了组合,而且组件又非常的多,如果Service是由很多组件构成的庞大的家伙,比如一个迷宫:假设一个迷宫是由三种不同的小单元组成,为房间,墙,门。
class Maze{ Room r1; Room r2; ... Wall w1; Wall w2; ... Door d1; Door d2; ... //构造器 Maze(){ //按顺序摆放成员字段组件 ... }}
问题是,要生成一个迷宫,要成百上千个门,墙,房组件。而且还要遵循一定的逻辑规则,因此构造器就会很复杂,迷宫有无数种,如果给每个迷宫都创建一个实体类,再给出具体构造流程,那就累死了。
这种情况下,合理的办法是写一个随机迷宫生成器,能根据具体要求不同生成无数种迷宫,这就是创建型模式的意义所在。无论是“虚拟工厂模式”,还是“生成器”模式,工厂模式,都是在具体生成的策略上做文章,但一个大前提不变:具体产出的产品Product都是由很多小的组件组合而成,而且组装的时候灵活度非常高,甚至是runtime用户定制的,或者是随机的。这就导致组合出来的产品Product单独作为一个类存在的意义很小,反而是构造器的作用被放大。索性把构造过程独立出来成为一个方法,把这个方法用到的参数作为成员字段一起封装起来,再来个构造器只负责初始化这些参数,这种累就是“工厂类”。
class MazeFactory{ //巨大迷宫生成算法 Maze mazeGenerator(int roomNum, int wallNum, int doorNum){ ... } //构造器 初始化生成迷宫的参数 MazeFactory(){ roomNum = 100; wallNum = 1000; doorNum = 200; } //字段:生成迷宫的参数 int roomNum; int wallNum; int doorNum;}
原来的那个迷宫类,本身的构造器不承担任何功能了。
class Maze{ void play(){...} Maze(int roomNum, int wallNum, int doorNum){ Room[] roomSet = new Room[roomNum]; Wall[] wallSet = new Wall[wallNum]; Door[] doorSet = new Door[doorSet]; } Room[] roomSet; Wall[] wallSet; Door[] doorSet;}
所以再回到工厂方法,书里说的所有的东西,都是基于这个前提,也就是我们说好了啊,迷宫这东西的类文件里是没有具体构造方法的,都是要用工厂类MazeFactory来生成的。至于后来,我们加入了方迷宫,和方迷宫生成器。又有了圆迷宫和圆迷宫生成器。有了一堆生成器复杂了之后,又想到用多态来解耦,这都是后话,是在确定了使用工厂类的前提下,利用多态解耦的优化方案。所以才有了最初的这段代码:
//两个接口interface Maze{ void play();}interface MazeFactory{ Maze mazeGenerator(); }//各自继承类CircularMaze implements Maze{ ...}SquareMaze implements Maze{ ...}CircularFactory implements MazeFactory{ ...}SquareMazeFactory implements MazeFactory{ ...}//多态,面向接口public static void mazeGame(MazeDactory fact){ Maze z = fact.mazeGenerator(); z.play();}
再来,如果程序为:
public static void serviceConsumer(Service s){ s.method1(); s.method2();}
Service从哪来呢?当然是从其他地方new了传进来:
Service s = new ServiceA();serviceConsumer(s);
Service为什么是一个接口?
ServiceA s = new ServiceA();s.method1();s.method2();
如果有一天,领导要求将数据库从MYSQL换成ACCESS,因为只有一个ServiceA所以只能把所有用到ServiceA的地方都替换成ServiceB:
//!ServiceA s = new ServiceB();ServiceB s = new ServiceB();s.method1();s.method2();
如果是个小项目,没关系,如果是一个庞大的团队项目,,,根据设计原则中的依赖倒置原则,设计一个接口,然后扩展一个类,这样就能灵活应对boss的需求了:
Service s;if (Config.DB == SQL) s = new ServiceA();else if (Config.DB == ACCESS) s = new ServiceB();s.method1();s.method2();
又过了几天,用到的数据库越来越多,if else也越来越多,我么你决定隔离这些变化,将Service实例化过程放在一个地方,简单工厂诞生:
Service s = ServiceFactory.getService(Config.DB);s.method1();s.method2();public class ServiceFactory{ public static Service getService(DB db){ if(db == SQL) return new SerivceA(); else if(db == ACCESS) return new ServiceB(); else return null; }}
这样,即时数据库不断变化,我也只需要扩展一个新的类,并且修改工厂这个类就行了。但是ServiceFactory是一个接口,这就是抽象工厂。
另一位回答者接下去回答:
如果只有一个工厂,但同一个Service在不同环境下会有不同的实现,如果环境很多,这个ServiceFactory会变成什么样呢:
class ServiceFactory{ Environment env; public static Service getService(){ if(env == MYSQL){ return new ServiceA(arg1, arg2,...) }else if (env == ORACLE){ return new ServiceB(arg1, arg2,...); }else if (env == BIG_TABLE){ return new ServiceC(arg1, arg2,...); } }}
那么if else越来越多,每次修改都需要重新编译整个Factory,而且,一般情况下,实现这些Service的往往是不同组的人,每个组都往这个类里加参数/状态,合并代码时会出现无数个冲突,还可能互相用错参数从而影响别人代码,抽象工厂大家的实现分开到不同的类里面,让大家各改各的文件,互不影响:
//小组1的文件:class MySqlFactory implements ServiceFactory{ public static Service getService(){ //计算 arg1, arg2,... return new ServiceA(arg1, arg2); }}//小组2的文件class OrcaleFactory implements ServiceFactory{ public static Service getService(){ //计算arg1, arg2, ... return new ServiceB(arg1, arg2); }}...
这些工厂不需要使用时才new,只要事先new好,存入一个Map,根据具体环境随时调用:
Map<Environment, ServiceFactory> factoryMap = new HashMap<>();factoryMap.put(MYSQL, new MySqlFactory());factoryMap.put(ORACLE, new OracleFactory());...
然后调用serviceConsumer的那个地方只需要:
Environment env = ...//获得环境变量envServiceFactory factory = factoryMap.get(env);serviceSonsumer(factory);
以后如果有新的数据库,重新写一个ServiceFactory的实现类,编译一下放一块就行,在factoryMap里放入实例就好了,别的代码完全不需要动,甚至不需要重新编译。
可不可以不要Factory,直接用ServiceMap呢?
Map<Environment, Service> serviceMap = new HashMap<>();serviceMap.put(MYSQL, new ServiceA(..));serviceMap.put(ORACLE, new ServiceB(..));
基本是不行的,首先Service的初始化一般需要很多参数,不可能在程序刚载入时就存在,另外Service的实例会new很多个,也不满足一一对应的关系。但Factory的构造函数一般不需要参数。相比于Service,Factory内部保存的仅仅是一些参数,占用内存小得多,长时间驻留在内存中也没有太大的损害。
- 工厂模式(工厂方法模式,抽象工厂模式) Java
- Java工厂模式(简单工厂、工厂方法、抽象工厂)
- java工厂模式-简单工厂,工厂方法,抽象工厂模式
- java学习之工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)
- JAVA之工厂模式(静态工厂模式(简单工厂模式)、工厂方法模式、抽象工厂模式)
- Java工厂模式 工厂方法模式 抽象工厂
- 工厂模式(简单工厂,工厂方法,抽象工厂)
- 工厂模式(简单工厂+工厂方法+抽象工厂)
- 工厂模式(简单工厂、工厂方法、抽象工厂)
- 工厂模式(简单工厂、工厂方法、抽象工厂)
- 工厂模式详解(简单工厂+工厂方法+抽象工厂)
- 工厂模式详解(简单工厂+工厂方法+抽象工厂)
- 工厂模式(简单工厂,工厂方法,抽象工厂)
- 工厂模式(简单工厂+工厂方法+抽象工厂)
- 工厂方法,抽象工厂模式
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式+抽象工厂模式)
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式+抽象工厂模式)
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式+抽象工厂模式)
- SQL基础笔记
- java程序性能优化
- 英文字体的选择
- 动态规划之序列的连配
- 挖掘出的NLP领域的牛人
- 工厂模式(工厂方法模式,抽象工厂模式) Java
- 10.SVM的优缺点
- c/c++面试题
- Android应用之——百度地图定位返回4.9E-324的解决方案
- 十大机器学习算法之Apriori
- OMXCodec与OMX事件处理流程
- 深入分析 Java I/O 的工作机制(网络 I/O 优化)
- 转行做软件编程开发的经历
- Shader山下(三)逐帧动画