工厂模式就好比将java中创建具体对象的方式带入了工厂时代,你可以轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程。 它是基于为创建对象提供了过渡接口,以便将创建对象的具体过程屏蔽起来,达到提高灵活性的目的。
工厂模式分类
工厂模式中一般分为三类,分别是简单工厂模式、工厂方法模式和抽象工厂模式。 我们举一个例子来说明这三种模式
假设现在苹果公司没有工厂,那么我们要一部 iphone6s 手机,那么他就要根据客户的需求单独生产一个 iphone6s 手机,来满足客户的需求。
现在苹果公司有了简单工厂(简单工厂模式),那么公司就不用为客户单独生产手机,工厂可以直接生产 iphone6s 手机,这时不仅可以生产 iphone6s 还可以生产其他型号,只要有型号说明就可以生产出对应的产品。
接下来随着苹果公司产量的大规模提升,每个型号的差异也有了很大的区别,一个工厂无法满足如此大量的需求,这时候就引进了多工厂(工厂方法模式),这时候总工厂(一个抽象类)负责生产所有 iphone 系列通用部分,各个子工厂负责生产对应型号的部分。
接下来随着客户的要求越来越高,iphone 必须配置蓝宝石玻璃。通过寻找合作厂商(interface接口)与各个子厂合作(实现这个接口),合作厂商来提供不同型号 iphone 的不同规格的蓝宝石玻璃
简单工厂模式
简单工厂模式又称为静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。我们根据 iphone 那个例子看看简答工厂模式中生产 iphone 的工厂的样子
/**
* 手机生产Iphone的简单工厂类
*
* @since 16/5/16.
*/
public class IPhoneFactory {
public IPhone create(String type) {
if (type.equalsIgnoreCase("6s")) {
return new IPhone6s();
} else if (type.equalsIgnoreCase("6")) {
return new IPhone6();
} else if (type.equalsIgnoreCase("5s")) {
return new IPhone5s();
} else {
return null;
}
}
}
我们可以看到,通过传入型号就可以生产相对应的 iphone 手机,然后我们来看一下 iphone 手机的类是什么样子,通过代码看一下被创建的实例通常都具有共同的父类这句话的意思
/**
* @since 16/5/16
*/
public class IPhone {
protected String name; //iphone的不同型号名字
public IPhone(){
packaging();
prepare();
}
public void packaging() {
System.out.println("组装手机零部件... ");
}
public void prepare() {
System.out.println("将手机装盒包装,贴防伪标签");
}
public String getName(){
return name;
}
}
class IPhone6s extends IPhone {
public IPhone6s() {
super();
this.name = "Iphone6s";
}
}
class IPhone6 extends IPhone {
public IPhone6() {
super();
this.name = "Iphone6";
}
}
class IPhone5s extends IPhone {
public IPhone5s() {
super();
this.name = "Iphone5s";
}
}
我们可以看到,iphone 的不同型号都是继承自一个 Iphone 这个父类,这样就通过多态的方式得到不同的型号的名字,然后我们看一下客户 user 是如何通过商店购买到 iphone 手机这个过程的
/**
* 手机商店
*
* @since 16/5/16.
*/
public class IPhoneStore {
private IPhoneFactory factory = new IPhoneFactory();
public IPhone sellIPhone(String type) {
IPhone iPhone = factory.create(type);
return iPhone;
}
}
/**
* 买IPhone的用户,直接去Iphone销售点(IPhoneStore)购买
*
* @since 16/5/16
*/
public class User {
private IPhoneStore store;
public static void main(String[] args) {
new User().buy("6");
}
public void buy(String type) {
store = new IPhoneStore();
IPhone iPhone = store.sellIPhone(type);
System.out.println("用户购买到"+iPhone.getName()) ;
}
}
User 客户通过简单的告诉商店型号需求,然后商店就会将工厂生产出对应的型号交给客户,这个流程就完成了,我们来看一下运行的效果
由于工厂类 IPhoneFactory 集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。同时我们要知道使用简单工厂模式将会增加系统中类的个数(以后还要添加 Iphone7 等类… ),在一定程序上增加了系统的复杂度和理解难度,这样也就存在着系统扩展困难的问题,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
根据上述的优缺点,我们分析出简单工厂模式适用场景
- 工厂类负责创建的对象比较少
由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,对于如何创建对象不关心
客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
工厂方法模式
工厂方法模式又称为多态工厂模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口(抽象类),而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。我们再通过 Iphone 那个例子来看看工厂方法模式
首先 Iphone 系列类不变和上面一样
/**
* @since 16/5/16
*/
public class IPhone {
protected String name; //iphone的不同型号名字
public IPhone() {
}
public void packaging() {
System.out.println("组装手机零部件... ");
}
public void prepare() {
System.out.println("将手机装盒包装,贴防伪标签");
}
public String getName() {
return name;
}
}
class IPhone6s extends IPhone {
public IPhone6s() {
super();
this.name = "Iphone6s";
}
}
class IPhone6 extends IPhone {
public IPhone6() {
super();
this.name = "Iphone6";
}
}
class IPhone5s extends IPhone {
public IPhone5s() {
super();
this.name = "Iphone5s";
}
}
我们看一下抽象的工厂方法类
/**
* 抽象类工厂
*
* @since 16/5/16
*/
public abstract class IphoneStore {
public abstract IPhone createIphone(String type);
public IPhone sellIphone(String type) {
IPhone iPhone = createIphone(type);
iPhone.prepare();
iPhone.packaging();
return iPhone;
}
}
这里我们将创建 Iphone 这个流程交给子工厂去处理,这样就可以灵活的添加子类工厂中特有的元素,比如我们下面的这个中国的苹果工厂就可以自定义贴上 “中国红” 的标签,如果都放在一个工厂中,那么类似中国工厂还有德国、英国、法国等等,会出现大量的 if 判断… 然我们看一下这个中国工厂(其他子工厂类似)
/**
* 中国生产Iphone6的厂子
*
* @since 16/5/16
*/
public class ChinaIphoneStore extends IphoneStore {
public ChinaIphoneStore() {
//自定义一些特有内容
System.out.println("贴上中国红标志 made in China");
}
@Override
public IPhone createIphone(String type) {
IPhone iPhone = null;
if ("6s".equals(type)) {
iPhone = new IPhone6s();
} else if ("6".equals(type)) {
iPhone = new IPhone6();
} else if ("5s".equals(type)) {
iPhone = new IPhone5s();
}
return iPhone;
}
}
这里最重要的就是父类的 create 方法是抽象的,需要交给子类进行自定义处理,然后我们看一下User是如何买到这个Iphone的
/**
* 买IPhone的用户
*
* @since 16/5/16
*/
public class User {
IphoneStore cStore;
public static void main(String[] args) {
new User().buy("5s");
}
/**
* 买一种型号的iphone
*
* @param type
*/
public void buy(String type) {
cStore = new ChinaIphoneStore();
IPhone iPhone = cStore.sellIphone(type);
System.out.println("用户购买到" + iPhone.getName());
}
}
这样就可以从中国的工厂买到 Iphone 的手机了,然后我们看一下执行的效果
在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
那么任何方式都是有利有弊的,采用工厂方法模式添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销
根据上述的优缺点,我们分析出简单工厂模式适用场景
- 一个类不知道它所需要的对象的类
在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
- 一个类通过其子类来指定创建哪个对象
在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性在程序运行时,子类覆盖父类对象,从而使得系统更容易扩展。
抽象工厂模式
抽象工厂为创建一组相关或相互依赖的对象提供一个接口,而无需指定他们的具体类。抽象工厂模式又称为 Kit 模式,属于对象创建型模式。我们接的说我们的 iphone 例子,前面说到 iphone 要嵌入蓝宝石玻璃,于是我们新建一个提供蓝宝石玻璃的接口
/**
* @since 16/5/16
*/
public interface GlassFactory {
/**
* 生产蓝宝石玻璃
*
* @return
*/
public Glass createGlass();
}
我们看一下配套的蓝宝石玻璃类
/**
* @since 16/5/16
*/
public class Glass {
public Glass() {
System.out.println("手机配备相应型号的蓝宝石玻璃");
}
}
然后在我们的中国厂商中加入这个合作Glass厂商(实现这个接口),通过代码我们看一下
/**
* 中国生产Iphone6的厂子
*
* @since 16/5/16
*/
public class ChinaIphoneStore extends IphoneStore implements GlassFactory{
public ChinaIphoneStore() {
forkChina();
}
@Override
public IPhone createIphone(String type) {
IPhone iPhone = null;
if ("6s".equals(type)) {
iPhone = new IPhone6s();
} else if ("6".equals(type)) {
iPhone = new IPhone6();
} else if ("5s".equals(type)) {
iPhone = new IPhone5s();
}
return iPhone;
}
public void forkChina(){
System.out.println("贴上中国红标志 made in China");
System.out.println("使用"+createGlass()+"做玻璃");
}
@Override
public Glass createGlass() {
return new Glass();
}
}
然后运行 User 类,我们可以看到下面这个效果
贴上中国红标志 made in China
手机配备相应型号的蓝宝石玻璃
使用Glass@71662a95做玻璃
将手机装盒包装,贴防伪标签
组装手机零部件…
用户购买到Iphone5s
我们可以看到,应用抽象工厂模式可以实现高内聚低耦合的设计目的,抽象工厂模式其实是工厂方法模式的一种扩展,应用抽象工厂模式可以创建一系列的产品(产品族),而不是像工厂方法模式中的只能创建一种产品。抽象工厂模式最大的缺点就是对产品族的扩展非常困难,如果要添加一个新的 “红宝石玻璃厂商” 的话,看看我们的改动会有多大吧… 首先要在Factory接口中声明新方法
HongBaoshiGlass createGlass()
然后在所有现有的工厂实现类中分别实现这个新的 createGlass() 方法,如果工厂类有很多,改动的地方也会很多的… 违反了开闭原则,并且作为契约的接口修改了,其他所有和接口有关的代码可能都要改。
总体来说,每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式针对的是多个产品等级结构。有多少个产品等级结构,就会在工厂角色中发现多少个工厂方法。每一个产品等级结构中有多少个具体的产品,就有多少个产品族,也就会在工厂等级结构中发现多少个具体工厂
那么关于工厂模式的设计方式就总结到这里