工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象 的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑 。工厂模式一般分为三种:简单工厂模式 、工厂方法模式 、抽象工厂模式 。
在这里简单说一下,本篇博客不仅仅是工厂模式,其中涉及到一些在学习工厂模式的时候所产生的一些疑问也给记录了下来。
一、为什么要有工厂模式
学习设计模式,往往有时候会想不通,我明明可以简单的实现,为什么还要搞的这么复杂,设计模式是一种设计思想 ,他的出现往往是多方面考虑 ,写代码不只是为完成功能,更多的需要考虑完成功能的基础之上日后维护起来怎么方便,要学会提升自己,而不是天天CRUD。
为什么要有工厂模式,工厂模式存在的意义是什么?我需要创建哪个对象直接new不就可以了吗,我相信一般学习工厂模式的前奏都会考虑这些,其实我也是。
我们以类Sample为例, 如果我们要创建Sample的实例对象:
Sample sample=new Sample();
可是,实际情况是,通常我们都要在创建sample实例时做点初始化的工作,比如赋值 查询数据库 等。
首先,我们想到的是,可以使用Sample的构造函数,这样生成实例就写成:
Sample sample=new Sample(参数);
场景一:如果创建sample实例时所做的初始化工作不是像赋值这样简单的事,可能是很长一段代码,如果也写入构造函数中,那你的代码很难看了。
初始化工作如果是很长一段代码,说明要做的工作很多,将很多工作装入一个方法中,相当于将很多鸡蛋放在一个篮子里,是很危险的,这也是有悖于Java面向对象的原则。
面向对象的封装 (Encapsulation)和分派 (Delegation)告诉我们,尽量将长的代码分派“切割”成每段,将每段再“封装”起来(减少段和段之间耦合联系性),这样,就会将风险分散,以后如果需要修改,只要更改每段,不会再发生牵一动百的事情。
在本例中,首先,我们需要将创建实例的工作 与使用实例的工作分开, 也就是说,让创建实例所需要的大量初始化工作从Sample的构造函数中分离出去 。这时我们就需要Factory工厂模式来生成对象了,不能再用上面简单new Sample(参数) 。
场景二:还有,如果Sample有个继承如MySample, 按照面向接口编程,我们需要将Sample抽象成一个接口.Sample是接口,有两个子类MySample 和HisSample .我们要实例化他们时,如下:
ISample mysample=new MySample();
ISample hissample=new HisSample();
随着项目的深入,Sample可能还会"生出很多儿子出来", 那么我们要对这些儿子一个个实例化,更糟糕的是,可能还要对以前的代码进行修改:加入后来生出儿子的实例.这在传统程序中是无法避免的.但如果你一开始就有意识使用了工厂模式,这些麻烦就没有了.
二、简单工厂模式
简单工厂模式不是23种里的一种,简而言之,就是有一个专门生产某个产品的类。
建立一个专门生产Sample实例的工厂:
public class Factory {
public static ISample creator(int which) {
if (which == 1)
return new MySample();
else if (which == 2)
return new HisSample();
return null;
}
}
interface ISample {
}
class MySample implements ISample {
}
class HisSample implements ISample {
}
那么在你的程序中,如果要创建ISample的实列时候可以使用
ISample sampleA=Factory.creator(1);
这样,在整个程序层面就不涉及到ISample的具体的实现类,我们只跟接口或者抽象类打交道,达到封装效果,也就减少错误修改的机会。
这个原理可以用很通俗的话来比喻:就是具体事情做得越多,越容易犯错误.这每个做过具体工作的人都深有体会,相反,官做得越高,说出的话越抽象越笼统,犯错误可能性就越少.好象我们从编程序中也能悟出人生道理。
使用工厂方法 要注意几个角色:
- 定义产品接口,如上面的Sample类的接口
- 产品接口下有ISample接口的实现类,如SampleA,
- 其次要有一个Factory类,用来生成产品ISample接口的具体实例。
三、工厂方法模式
工厂模式也就是鼠标工厂是个父类,有生产鼠标这个接口。 戴尔鼠标工厂,惠普鼠标工厂继承它,可以分别生产戴尔鼠标,惠普鼠标。 生产哪种鼠标不再由参数决定,而是创建鼠标工厂时决定。 假如创建戴尔鼠标工厂。后续直接调用鼠标工厂.生产鼠标()即可。
四、抽象工厂模式
抽象工厂模式也就是不仅生产鼠标,同时生产键盘。 也就是PC厂商是个父类,有生产鼠标,生产键盘两个接口。 戴尔工厂,惠普工厂继承它,可以分别生产戴尔鼠标+戴尔键盘,和惠普鼠标+惠普键盘。 假如创建戴尔鼠标工厂。 后续工厂.生产鼠标()则生产戴尔鼠标,工厂.生产键盘()则生产戴尔键盘。 假设我们增加耳麦这个产品,则首先我们需要增加耳麦这个父类,再加上戴尔耳麦,惠普耳麦这两个子类。
之后在PC厂商这个父类中,增加生产耳麦的接口。最后在戴尔工厂,惠普工厂这两个类中,分别实现生产戴尔耳麦,惠普耳麦的功能。
五、工厂方法模式和抽象工厂区别
抽象工厂模式把产品进行了两个纬度的划分,其中一个纬度是从产品本身派生出来的,鼠标、键盘、麦克风这些产品类别的划分。另外一个纬度是从工厂派生出来的,有不同品牌的工厂。
而工厂方法模式只有一个纬度,产品和工厂是完全对应的。
|