【java】设计模式之工厂模式

来源:互联网 发布:手机唱歌调音软件 编辑:程序博客网 时间:2024/05/17 07:37

学设计模式,我们要知道这个设计模式是用来解决什么问题的,并且知道,所有设计模式的设计初衷都是为了让代码更加符合面向对象的原则。

但是对于像我这样工作经验不多的小白,面对一些设计模式的确很难想到相应的应用场景,尤其是对于刚毕业的大学生。这种情况下不如先看看它的代码。


工厂模式有简单工厂模式(静态工厂模式),工厂方法模式和抽象工厂模式。


首先是简单工厂模式,

定义:由一个对象决定实例化接口的哪一个子类。

(这里的“决定”,不是让对象决定,而是对象(的这个方法)有了实例化不同类的权利,就是说,代码写完,我都不一定知道实际运行时,工厂会产生什么对象,但是我赋予了它产生一类(接口的子类)对象的权利)

假设:这个社会有一个种产品,客户端购买,那么,我们可以这样写:

public class Product {private String name;public Product(String name) {this.name = name;}}

Product p = new Product();
然后,社会进步了,这种产品出现了三个类型(第一种,第二种,第三种);
你可以这样写:
Product p1 = new Product(“first”);Product p2 = new Product(“second”);Product p3 = new Product(“third");

如果出现一万种,你的客户端是不是都这样写了呢?你发现问题了吗,既然客户端购买这个产品,当客户端又兼顾生产这种产品的职责(new Product())。
不如把这个工作,交给一个工厂,这个工厂负责生产不同的产品,而你只需要告诉他你要什么就好了,产品类的初始化交给它去做

这是类图


接口IProduct,public方法 show()。

public interface IProduct { public void show();}

下面有三个类,FirstProduct,SecondProduct,ThirdProduct。

就只贴一个吧。

public class FirstProduct implements IProduct {@Overridepublic void show() {System.out.println("第一个零件");}}

工厂类,Factory,它有一个静态方法,返回接入IProduct实例的make方法。(不要静态也行,客户端可以实例化一个工厂类,有了静态方法就不用实例化工厂类了)

public class Factory {public static IProduct make(int i) {if(i==1){return new FirstProduct() ;}if(i==2){return new SecondProduct() ;}if(i==3){return new ThirdProduct() ;}return null;}

测试类代码:

public static void main(String[] args) {IProduct product1 = Factory.make(1);IProduct product2 = Factory.make(2);IProduct product3 = Factory.make(3);product1.show();product2.show();product3.show();}

这样,类的初始化,由客户端,转移到工厂类里面。

如果不用接口,工厂想要生产这么多产品,必须针对每一个产品类,都要写一个方法,(改天写一篇面向接口编程的心得,推荐看head first 设计模式-工厂模式篇,它谈到需求改变,A a = new A()的不迎合变化的缺点,它认为简单工厂更像是一种编程习惯而非模式,事实上,简单工厂模式也非GOF的二十三种模式之一)

而且,夜不能放在一个方法里面。如果放在一个方法里面,返回类型是什么?所以,接口的出现,让这些类可以用同一个返回类型,这个返回类型就是“继承了这个借口的所有子类的类型”。

工厂模式的这一个点很重要——“延迟始化”(Lazy Initialization)。

延迟始化,顾名思义,延迟初始化,延迟产品类的初始化。

为什么要延迟初始化?很多情况下,我们需要在类初始化的时候,做一些事情,ok,我们可以把这些东西放到了这个类的构造方法里面,可是,有时候又需要处理另外一些情况怎么办?加判断条件,或者写约束。但这无疑加重的类的任务,增加了耦合度,这不符合我们的OO设计理念。

我们要处理的这些情况也不能交给客户端去做。所以,我们把这些事情,放到延迟初始化里面。

除此之外,还可以这样利用:在我们的类的实例可以重复利用的情况下,假如,这个类已经实例化过了, 何不返回一个已经产生的实例?

简单说一下,上面的代码没有写出。就是在工厂类里面,私有一个泛型为IProduct的arraylist,然后在make方法里面,判断一下,当前需要初始化的这个类有没有被初始化过,如果没有,那么初始化,存入arraylist,然后返回实例,如果有,直接从arraylist里面取出,返回。

当然,延迟始化还有很多作用,这里脑洞就不开太大了。我也突然发现我之前遇到的一些问题,可以用延迟始化来解决:比如,对不同类,不同情况下,初始化的处理,如果在每一个类自己的初始化里面做各种分析、条件判断,不仅找起来麻烦,找到也不好修改,不如都放在工厂的make方法下,便于处理,最起码代码好看多了,也方便。

亲娘来,我就是回顾一下以前学的东西,俩小时过去了。

推荐一本书《设计模式之禅》,真心不错。

顺带说一句,书这个东西嘛,没事多找几本自己可能会用到的书,存着,等哪天用到了查就好了,没有必要一口气看下来,你要是时间多,系统地看也无妨。

话说这些年我买的书,没有一本全看完的,都是看对当时的我有用的部分,或者 需要的时候查看一下。

无生也有涯,而知也无涯, 以有涯随无涯,岂不傻叉嘛。


接下来是 工厂方法模式。

定义:定义了一个创造对象的接口,由其子类决定实例化的类是哪一个。工厂方法让类把实例化推迟到了子类。

其实工厂方法模式就是在简单工厂模式之上,给工厂抽一个一个接口。

为啥么呢。假如,我们又有了新的产品,新的工厂,怎么办?在原有的工厂的make方法里加判断?这不符合OCP。

那么我们另起一个工厂。但是如果之后又加了新的产品、新的工厂,你能想象客户端乱七八糟的样子吗?

所以,所有工厂抽取一个工厂接口,这样,就符合OCP原则了。


这是类图,Factory1只生产Product1和Product2两种产品,Factory2只生产Product3这种产品,这样我们就不用修改原来的代码,从而让产品3进入市场了,嘿嘿。

public static void main(String[] args) {IFactory factoryA = new Factory1();IFactory factoryB = new Factory1();IProduct productA = factoryA.createProduct(1);productA.productMethdod();IProduct productB = factoryB.createProduct(3);productB.productMethdod();}
这是“市场”(客户端)

或许你会说“这样看来,简单工厂模式并不完全符合OCP原则啊”。是啊,但是那也要看在什么情况下,如果产品是人类的话,区别产品的条件是性别,无非有 男、女、无性别、双性人这四种。在既有条件下,不会出现新的产品,那么简单工厂和工厂方法都符合OCP。你可能会想到:对啊现在有ABC三种商品,如果这些商品区分男女,或者用其他条件分类怎么办?这就是下面要说的-抽象工厂模式。


抽象工厂模式。

定义:为创建一组相关或相互依赖的对象,提供一个接口,且无需指明具体的对象。

在说抽象工厂之前,明确一个态度,那就是:提出设计模式是为了解决问题,但是,并不是说,给你一个问题,你绕过了设计模式寻求其他的方法,或许在这个问题面前,确实有其他的解决办法,但我们谈的是设计模式,所以就说设计模式。

假设:市面上有产品A ,产品B,工厂1能生产出男人用的A 和 B,而工厂2生产出女人用的 A 和 B。

在这里,要了解一个概念,产品族和产品等级结构。上述提到的,产品A和产品B,是属于同一个产品等级结构,但是男用AB和女用AB,就是不同的产品族。

类图:


产品接口IProductA和IProductB将产品分为2种,A和B。

工厂接口声明了两种方法,生产A和生产B。

因为要生产这两种的产品,所以工厂接口代码如下:

public interface IFactory {public IProductA makeProductA();public IProductB makeProductB();}

Factory1.java

public class Factory1 implements IFactory {@Overridepublic IProductA makeProductA() {return new ProductA1();}@Overridepublic IProductB makeProductB() {return new ProductB1();}}
Factory2.java

public class Factory2 implements IFactory {@Overridepublic IProductA makeProductA() {return new ProductA2();}@Overridepublic IProductB makeProductB() {return new ProductB2();}}
产品类就列出一个:

public class ProductA1 implements IProductA {@Overridepublic void show() {System.out.println("产品A1");}}
test.java

public static void main(String[] args) {IFactory factory1 = new Factory1();IFactory factory2 = new Factory2();IProductA pA1 = factory1.makeProductA();IProductB pB1 = factory1.makeProductB();IProductA pA2 = factory2.makeProductA();IProductB pB2 = factory2.makeProductB();System.out.println("这是工厂1,生产:");pA1.show();pB1.show();System.out.println("这是工厂2,生产:");pA2.show();pB2.show();}

运行结果:


抽象工厂模式是针对多个产品等级结构,所以在工厂接口里,对与每一个产品接口,它都要有一个方法。或许你会问,那这样的话, 添加新种类的产品怎么办?工厂接口里是不是要修改呢?

是的,就是要修改,但是呢,有利就有弊,反之亦然。抽象工厂模式下,工厂是用来创造一个产品族的,而工厂方法模式下,工厂只是用来创造产品,不用考虑产品族的问题。

我们的目的是解耦,根据不同的情况,选择适合的模式。

1 0
原创粉丝点击