在我们平常创建对象的时候,都是通过关键字 new 来实现的,例:Class A = new A() 。
在一些情况下,要创建的对象需要一系列复杂的初始化操作,比如查配置文件、查数据库表、初始化成员对象等,如果把这些逻辑放在构造函数中,会极大影响代码的可读性。不妨定义一个类来专门负责对象的创建,这样的类就是工厂类,这种做法就是工厂模式,在任何需要生成复杂对象的地方,都可以使用工厂模式。
工厂模式包括:简单工厂(不在23种设计模式中)、工厂方法和抽象工厂。
简单工厂
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类。
- 抽象类或接口:定义了要创建的产品对象的接口。
- 具体实现:具有统一父类的具体类型的产品。
- 产品工厂:负责创建产品对象。工厂模式同样体现了开闭原则,将“创建具体的产品实现类”这部分变化的代码从不变化的代码“使用产品”中分离出来,之后想要新增产品时,只需要扩展工厂的实现即可。
/*
一个栗子:
我喜欢吃面条,抽象一个面条基类,(接口也可以),这是产品的抽象类。
*/
abstract class INoodles {
/**
* 描述每种面条啥样的
*/
public abstract void desc();
}
/**
*先来一份兰州拉面(具体的产品类):
*/
class LzNoodles extends INoodles {
@Override
public void desc() {
System.out.println("兰州拉面 上海的好贵 家里才5 6块钱一碗");
}
}
/**
* 程序员加班必备也要吃泡面(具体的产品类):
* 复制代码
*/
class PaoNoodles extends INoodles {
@Override
public void desc() {
System.out.println("泡面好吃 可不要贪杯");
}
}
/**
* 还有我最爱吃的家乡的干扣面(具体的产品类):
* 复制代码
*/
class GankouNoodles extends INoodles {
@Override
public void desc() {
System.out.println("还是家里的干扣面好吃 6块一碗");
}
}
/**
* 太和版面
*/
class TaihePanmian extends INoodles {
@Override
public void desc() {
System.out.println("太和板面");
}
}
/**
* 简单工厂模式
*/
class SimpleNoodlesFactory {
private static final int TYPE_LZ = 1;//兰州拉面
private static final int TYPE_PM = 2;//泡面
private static final int TYPE_GK = 3;//干扣面
private static final int TYPE_TH = 4;//太和板面
INoodles createNoodles(int type) {
switch (type) {
case TYPE_LZ:
return new LzNoodles();
case TYPE_PM:
return new PaoNoodles();
case TYPE_GK:
return new GankouNoodles();
case TYPE_TH:
return new TaihePanmian();
default:
return null;
}
}
}
public class test {
public static void main(String[] args) {
SimpleNoodlesFactory simpleNoodlesFactory=new SimpleNoodlesFactory();
INoodles iNoodles;
iNoodles=simpleNoodlesFactory.createNoodles(2);
iNoodles.desc();
iNoodles=simpleNoodlesFactory.createNoodles(4);
iNoodles.desc();
}
}
特点
1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。缺点
1 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
2 不同的产品需要不同额外参数的时候 不支持。工厂方法模式
1.模式描述
提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例。2.模式作用
可以一定程度上解耦,消费者和产品实现类隔离开,只依赖产品接口(抽象产品),产品实现类如何改动与消费者完全无关。
可以一定程度增加扩展性,若增加一个产品实现,只需要实现产品接口,修改工厂创建产品的方法,消费者可以无感知(若消费者不关心具体产品是什么的情况)。
可以一定程度增加代码的封装性、可读性。清楚的代码结构,对于消费者来说很少的代码量就可以完成很多工作。
等等。//TODO
另外,抽象工厂才是实际意义的工厂模式,工厂方法只是抽象工厂的一个比较常见的情况。
为了解决上面提到的”增加if-else”的问题,可以为每一个键盘子类建立一个对应的工厂子类,这些工厂子类实现同一个抽象工厂接口。这样,创建不同品牌的键盘,只需要实现不同的工厂子类。当有新品牌加入时,新建具体工厂继承抽象工厂,而不用修改任何一个类。
结构
- 抽象工厂:声明了工厂方法的接口。
- 具体产品工厂:实现工厂方法的接口,负责创建产品对象。
- 产品抽象类或接口:定义工厂方法所创建的产品对象的接口。
- 具体产品实现:具有统一父类的具体类型的产品。
```
/
一个栗子:
我喜欢吃面条,抽象一个面条基类,(接口也可以),这是产品的抽象类。
/
abstract class INoodles {
/**
- 描述每种面条啥样的 */ public abstract void desc(); }
/ 先来一份兰州拉面(具体的产品类): / class LzNoodles extends INoodles { @Override public void desc() { System.out.println(“兰州拉面 上海的好贵 家里才5 6块钱一碗”); } } /
- 太和版面 */
class TaihePanmian extends INoodles { @Override public void desc() { System.out.println(“太和板面”); } } /**
- 工厂类的接口 / interface INoodlesFactory { INoodles createProduct(); } /*
兰州拉面工厂 */ class LzNoodlesFactory implements INoodlesFactory{
@Override public INoodles createProduct() {
return new LzNoodles();
} } /**
泰和工厂 */ class TaiHeNoodlesFactory implements INoodlesFactory{
@Override public INoodles createProduct() {
return new TaihePanmian();
} }
public class test { public static void main(String[] args) { INoodlesFactory iNoodlesFactory=new TaiHeNoodlesFactory(); INoodles product= iNoodlesFactory.createProduct(); product.desc(); iNoodlesFactory=new LzNoodlesFactory(); product=iNoodlesFactory.createProduct(); product.desc(); } }
<a name="EFzQh"></a>
## **抽象工厂**
为了缩减工厂实现子类的数量,不必给每一个产品分配一个工厂类,可以将产品进行分组,每组中的不同产品由同一个工厂类的不同方法来创建。<br />例如,键盘、主机这2种产品可以分到同一个分组——电脑,而不同品牌的电脑由不同的制造商工厂来创建。<br /><br />类似这种把产品类分组,组内不同产品由同一工厂类的不同方法实现的设计模式,就是抽象工厂模式。<br />抽象工厂适用于以下情况:<br />1. 一个系统要独立于它的产品的创建、组合和表示时;<br />2. 一个系统要由多个产品系列中的一个来配置时;<br />3. 要强调一系列相关的产品对象的设计以便进行联合使用时;<br />4. 当你提供一个产品类库,而只想显示它们的接口而不是实现时;
<a name="0343f30d"></a>
### 抽象工厂模式与工厂方法模式的区别
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。<br /> 在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。
<a name="4mXFK"></a>
### 结构

- 抽象工厂:声明了创建抽象产品对象的操作接口。
- 具体产品工厂:实现了抽象工厂的接口,负责创建产品对象。
- 产品抽象类或接口:定义一类产品对象的接口。
- 具体产品实现:定义一个将被相应具体工厂创建的产品对象。
interface Keyboard { void print(); } class DellKeyboard implements Keyboard { @Override public void print() { //…dell…dell; System.out.println(“dell 键盘”); } } class HPKeyboard implements Keyboard { @Override public void print() { //…HP…HP; System.out.println(“hp 键盘”); } } interface Monitor { void play(); } class DellMonitor implements Monitor { @Override public void play() { //…dell…dell; System.out.println(“dell play”); } } class HPMonitor implements Monitor { @Override public void play() { //…HP…HP; System.out.println(“Hp display”); } } interface MainFrame { void run(); } class DellMainFrame implements MainFrame { @Override public void run() { //…dell…dell; System.out.println(“dell 框架”); } } class HPMainFrame implements MainFrame { @Override public void run() { //…HP…HP; System.out.println(“hp 框架”);
}
} //工厂类。工厂分为Dell工厂和HP工厂,各自负责品牌内产品的创建 interface IFactory { MainFrame createMainFrame(); Monitor createMonitor(); Keyboard createKeyboard(); } class DellFactory implements IFactory { @Override public MainFrame createMainFrame(){ MainFrame mainFrame = new DellMainFrame(); //…造一个Dell主机; return mainFrame; } @Override public Monitor createMonitor(){ Monitor monitor = new DellMonitor(); //…造一个Dell显示器; return monitor; } @Override public Keyboard createKeyboard(){ Keyboard keyboard = new DellKeyboard(); //…造一个Dell键盘; return keyboard; } } class HPFactory implements IFactory { @Override public MainFrame createMainFrame(){ MainFrame mainFrame = new HPMainFrame(); //…造一个HP主机; return mainFrame; } @Override public Monitor createMonitor(){ Monitor monitor = new HPMonitor(); //…造一个HP显示器; return monitor; } @Override public Keyboard createKeyboard(){ Keyboard keyboard = new HPKeyboard(); //…造一个HP键盘; return keyboard; } } //客户端代码。实例化不同的工厂子类,可以通过不同的创建方法创建不同的产品 public class test { public static void main(String[] args) { IFactory dellFactory = new DellFactory(); IFactory hPFactory = new HPFactory(); //创建戴尔 Keyboard keyboard = dellFactory.createKeyboard(); MainFrame mainFrame=dellFactory.createMainFrame(); Monitor monitor=dellFactory.createMonitor(); keyboard.print(); mainFrame.run(); monitor.play(); //创建惠普 keyboard = hPFactory.createKeyboard(); mainFrame=hPFactory.createMainFrame(); monitor=hPFactory.createMonitor(); keyboard.print(); mainFrame.run(); monitor.play(); } } ```
优缺点
增加分组非常简单,例如要增加Lenovo分组,只需创建Lenovo工厂和具体的产品实现类。分组中的产品扩展非常困难,要增加一个鼠标Mouse,既要创建抽象的Mouse接口, 又要增加具体的实现:DellMouse、HPMouse, 还要再每个Factory中定义创建鼠标的方法实现。
总结
- 简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象。
- 工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断。
- 抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。
在下述情况下可以考虑使用工厂模式:
- 在编码时不能预见需要创建哪种类的实例。
- 系统不应依赖于产品类实例如何被创建、组合和表达的细节。
总结
无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。
所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。