设计模式3---工厂模式(Factory Pattern简单工厂、工厂方法、抽象工厂)
工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类。
工厂模式的形态
工厂模式主要用一下几种形态:
1:简单工厂(Simple Factory)。
2:工厂方法(Factory Method)。
3:抽象工厂(Abstract Factory)。
简单工厂(Simple Factory)
又叫静态工厂,是工厂模式三中状态中结构最为简单的。主要有一个静态方法,用来接受参数,并根据参数来决定返回实现同一接口的不同类的实例。我们来看一个具体的例子:
假设一家工厂,几生产洗衣机,有生产冰箱,还有空调等等..
我们先为所有产品定义一个共同的产品接口
- public interface Product{}
接着我们让这个工厂的所有产品都必须实现此接口
- public class Washer implements Product{
- public Washer(){
- System.out.println("洗衣机被制造了");
- }
- }
- public class Icebox implements Product{
- public Icebox(){
- System.out.println("冰箱被制造了");
- }
- }
- public class AirCondition implements Product{
- public Icebox(){
- System.out.println("空调被制造了");
- }
- }
接下来我们来写一个工厂类,有它来负责生产以上的产品
- public class SimpleFactory {
- public static Product factory(String productName) throws Exception{
- if(productName.equals("Washer")){
- return new Washer();
- }else if(productName.equals("Icebox")){
- return new Icebox();
- }else if(productName.equals("AirCondition")){
- return new AirCondition();
- }else{
- throw new Exception("没有该产品");
- }
- }
- }
好了,有了这个工厂类,我们就可以开始下定单了,SimpleFactory将根据不同的定单类决定生产什么产品。
- public static void main(String[] args) {
- try {
- SimpleFactory.factory("Washer");
- SimpleFactory.factory("Icebox");
- SimpleFactory.factory("AirCondition");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
由上面的代码可以看出,简单工厂的核心就是一个SimpleFactory类,他拥有必要的逻辑判断能力和所有产品的创建权利,我们只需要向把定单给他,就能得到我们想要的产品。这使用起来似乎非常方便。
但,实际上,这个SimpleFactory有很多的局限。首先,我们每次想要增加一种新产品的时候,都必须修改SimpleFactory的原代码。其次,当我们拥有很多很多产品的时候,而且产品之间又存在复杂的层次关系的时候,这个类必须拥有复杂的逻辑判断能力,其代码量也将不断地激增,这对以后的维护简直就是恐怖两个字...
还有就是,整个系统都严重依赖SimpleFactory类,只要SimpleFactory类一出问题,系统就进入不能工作的状态,这也是最为致命的一点....
以上的不足将在工厂模式的另外两种状态中得到解决。
工厂方法(Factory Method)
上面的代码告诉我们,简单工厂并不简单,它是整个模式的核心,一旦他出了问题,整个模式都将受影响而不能工作,为了降低风险和为日后的维护、扩展做准备,我们需要对它进行重构,引入工厂方法。
工厂方法为工厂类定义了接口,用多态来削弱了工厂类的职能,以下是工厂接口的定义:
- public interface Factory{
- public Product create();
- }
我们再来定义一个产品接口
- public interface Product{}
一下是实现了产品接口的产品类
- public class Washer implements Product{
- public Washer(){
- System.out.println("洗衣机被制造了");
- }
- }
- public class Icebox implements Product{
- public Icebox(){
- System.out.println("冰箱被制造了");
- }
- }
- public class AirCondition implements Product{
- public Icebox(){
- System.out.println("空调被制造了");
- }
- }
接下来,就是工厂方法的核心部分,也就是具体创建产品对象的具体工厂类,
- //创建洗衣机的工厂
- public class CreateWasher implements Factory{
- public Product create(){
- return new Washer();
- }
- }
- //创建冰箱的工厂
- public class CreateIcebox implements Factory{
- public Product create(){
- return new Icebox();
- }
- }
- //创建空调的工厂
- public class CreateAirCondition implements Factory{
- public Product create(){
- return new AirCondition();
- }
- }
从上面创建产品对象的代码可以看出,工厂方法和简单工厂的主要区别是,简单工厂是把创建产品的职能都放在一个类里面,而工厂方法则把不同的产品放在实现了工厂接口的不同工厂类里面,这样就算其中一个工厂类出了问题,其他工厂类也能正常工作,互相不受影响,以后增加新产品,也只需要新增一个实现工厂接口工厂类,就能达到,不用修改已有的代码。但工厂方法也有他局限的地方,那就是当面对的产品有复杂的等级结构的时候,例如,工厂除了生产家电外产品,还生产手机产品,这样一来家电是手机就是两大产品家族了,这两大家族下面包含了数量众多的产品,每个产品又有多个型号,这样就形成了一个复杂的产品树了。如果用工厂方法来设计这个产品家族系统,就必须为每个型号的产品创建一个对应的工厂类,当有数百种甚至上千种产品的时候,也必须要有对应的上百成千个工厂类,这就出现了传说的类爆炸,对于以后的维护来说,简直就是一场灾难.....
抽象工厂(Abstract Factory)
抽象工厂:意的意图在于创建一系列互相关联或互相依赖的对象。<<Java设计模式>>
我自己觉得抽象工厂是在工厂方法的基础上引进了分类管理的概念....
工厂方法用来创建一个产品,它没有分类的概念,而抽象工厂则用于创建一系列产品,所以产品分类成了抽象工厂的重点,
我们继续用上面的例子来说明:
工厂生产的所有产品都用都用大写字母来标明它们的型号,比如冰箱,就有“冰箱-A",“冰箱-B",同样,其他的产品也都是遵守这个编号规则,于是就有了一下产品家族树
冰箱:
- 冰箱-A
- 冰箱-B
洗衣机:
- 洗衣机-A
- 洗衣机-B
我们可以为冰箱和洗衣机分别定义两个产品接口,以对他们进行分类,
- //洗衣机接口
- public interface Washer{
- }
- //冰箱接口
- public interface Icebox{
- }
接着,我们分别创建这两个接口的具体产品
- //洗衣机-A
- public class WasherA implements Washer{
- public WasherA(){
- System.out.println("洗衣机-A被制造了");
- }
- }
- //洗衣机-B
- public class WasherB implements Washer{
- public WasherB(){
- System.out.println("洗衣机-B被制造了");
- }
- }
- //冰箱-A
- public class IceboxA implements Icebox{
- public IceboxA(){
- System.out.println("冰箱-A被制造了");
- }
- }
- //冰箱-B
- public class IceboxB implements Icebox{
- public IceboxB(){
- System.out.println("冰箱-B被制造了");
- }
- }
到此,产品部分我们准备好了,接下来我们来处理工厂部分,我们先来定义工厂行为接口
- public interface Factory{
- public Washer createWasher();
- public Icebox createIcebox();
- }
接下来我创造具体的工厂类,我们根据上面产品的接口,把型号A的产品分为一类,由一个工厂来管理,把型号为B的产品有另一个工厂管理,根据这个分类,我们可以实现如下的两个具体工厂类
- //创建型号为A的产品工厂
- public class FactoryA implements Factory{
- //创建洗衣机-A
- public Washer createWasher(){
- return new WasherA();
- }
- //创建冰箱-A
- public Icebox createIcebox(){
- return new IceboxA();
- }
- }
- //创建型号为B的产品工厂
- public class FactoryB implements Factory{
- //创建洗衣机-B
- public Washer createWasher(){
- return new WasherB();
- }
- //创建冰箱-B
- public Icebox createIcebox(){
- return new IceboxB();
- }
- }
===============================================================================
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。包括:简单工厂模式,工厂方法模式,抽象工厂模式三种。
类型:创建类模式
类图:
工厂方法模式代码
- interface IProduct {
- public void productMethod();
- }
- class Product implements IProduct {
- public void productMethod() {
- System.out.println("产品");
- }
- }
- interface IFactory {
- public IProduct createProduct();
- }
- class Factory implements IFactory {
- public IProduct createProduct() {
- return new Product();
- }
- }
- public class Client {
- public static void main(String[] args) {
- IFactory factory = new Factory();
- IProduct prodect = factory.createProduct();
- prodect.productMethod();
- }
- }
工厂模式:
首先需要说一下工厂模式。工厂模式根据抽象程度的不同分为三种:简单工厂模式(也叫静态工厂模式)、本文所讲述的工厂方法模式、以及抽象工厂模式。工厂模式是编程中经常用到的一种模式。它的主要优点有:
- 可以使代码结构清晰,有效地封装变化。在编程中,产品类的实例化有时候是比较复杂和多变的,通过工厂模式,将产品的实例化封装起来,使得调用者根本无需关心产品的实例化过程,只需依赖工厂即可得到自己想要的产品。
- 对调用者屏蔽具体的产品类。如果使用工厂模式,调用者只关心产品的接口就可以了,至于具体的实现,调用者根本无需关心。即使变更了具体的实现,对调用者来说没有任何影响。
- 降低耦合度。产品类的实例化通常来说是很复杂的,它需要依赖很多的类,而这些类对于调用者来说根本无需知道,如果使用了工厂方法,我们需要做的仅仅是实例化好产品类,然后交给调用者使用。对调用者来说,产品所依赖的类都是透明的。
工厂方法模式:
通过工厂方法模式的类图可以看到,工厂方法模式有四个要素:
- 工厂接口。工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。在实际编程中,有时候也会使用一个抽象类来作为与调用者交互的接口,其本质上是一样的。
- 工厂实现。在编程中,工厂实现决定如何实例化产品,是实现扩展的途径,需要有多少种产品,就需要有多少个具体的工厂实现。
- 产品接口。产品接口的主要目的是定义产品的规范,所有的产品实现都必须遵循产品接口定义的规范。产品接口是调用者最为关心的,产品接口定义的优劣直接决定了调用者代码的稳定性。同样,产品接口也可以用抽象类来代替,但要注意最好不要违反里氏替换原则。
- 产品实现。实现产品接口的具体类,决定了产品在客户端中的具体行为。
前文提到的简单工厂模式跟工厂方法模式极为相似,区别是:简单工厂只有三个要素,他没有工厂接口,并且得到产品的方法一般是静态的。因为没有工厂接口,所以在工厂实现的扩展性方面稍弱,可以算所工厂方法模式的简化版,关于简单工厂模式,在此一笔带过。
适用场景:
不管是简单工厂模式,工厂方法模式还是抽象工厂模式,他们具有类似的特性,所以他们的适用场景也是类似的。
首先,作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
其次,工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以考虑使用工厂模式。将会大大降低对象之间的耦合度。
再次,由于工厂模式是依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性比较好。也就是说,当需要系统有比较好的扩展性时,可以考虑工厂模式,不同的产品用不同的实现工厂来组装。
典型应用
要说明工厂模式的优点,可能没有比组装汽车更合适的例子了。场景是这样的:汽车由发动机、轮、底盘组成,现在需要组装一辆车交给调用者。假如不使用工厂模式,代码如下:
- class Engine {
- public void getStyle(){
- System.out.println("这是汽车的发动机");
- }
- }
- class Underpan {
- public void getStyle(){
- System.out.println("这是汽车的底盘");
- }
- }
- class Wheel {
- public void getStyle(){
- System.out.println("这是汽车的轮胎");
- }
- }
- public class Client {
- public static void main(String[] args) {
- Engine engine = new Engine();
- Underpan underpan = new Underpan();
- Wheel wheel = new Wheel();
- ICar car = new Car(underpan, wheel, engine);
- car.show();
- }
- }
可以看到,调用者为了组装汽车还需要另外实例化发动机、底盘和轮胎,而这些汽车的组件是与调用者无关的,严重违反了迪米特法则,耦合度太高。并且非常不利于扩展。另外,本例中发动机、底盘和轮胎还是比较具体的,在实际应用中,可能这些产品的组件也都是抽象的,调用者根本不知道怎样组装产品。假如使用工厂方法的话,整个架构就显得清晰了许多。
- interface IFactory {
- public ICar createCar();
- }
- class Factory implements IFactory {
- public ICar createCar() {
- Engine engine = new Engine();
- Underpan underpan = new Underpan();
- Wheel wheel = new Wheel();
- ICar car = new Car(underpan, wheel, engine);
- return car;
- }
- }
- public class Client {
- public static void main(String[] args) {
- IFactory factory = new Factory();
- ICar car = factory.createCar();
- car.show();
- }
- }
使用工厂方法后,调用端的耦合度大大降低了。并且对于工厂来说,是可以扩展的,以后如果想组装其他的汽车,只需要再增加一个工厂类的实现就可以。无论是灵活性还是稳定性都得到了极大的提高。
==============================================================================
Java 之工厂方法和抽象工厂模式
1. 概念
工厂方法:一抽象产品类派生出多个具体产品类;一抽象工厂类派生出多个具体工厂类;每个具体工厂类只能创建一个具体产品类的实例。
即定义一个创建对象的接口(即抽象工厂类),让其子类(具体工厂类)决定实例化哪一个类(具体产品类)。“一对一”的关系。
抽象工厂:多个抽象产品类,派生出多个具体产品类;一个抽象工厂类,派生出多个具体工厂类;每个具体工厂类可创建多个具体产品类的实例。
即提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们的具体的类。“一对多”的关系。
2. UML
工厂方法:
抽象工厂:
3. 代码
工厂方法:
public interface Product
{
} public interface Creator
{
public Product factory();
} public class ConcreteProduct1 implements Product
{
public ConcreteProduct1()
{
System.out.println("ConcreteProduct1被创建");
}
} public class ConcreteProduct2 implements Product
{
public ConcreteProduct2()
{
System.out.println("ConcreteProduct2被创建");
} } public class ConcreteCreator1 implements Creator
{
public Product factory()
{
return new ConcreteProduct1();
}
} public class ConcreteCreator2 implements Creator
{
public Product factory()
{
return new ConcreteProduct2();
}
} public class Client
{
private static Creator creator1, creator2;
private static Product prod1, prod2; public static void main(String[] args)
{
creator1 = new ConcreteCreator1();
prod1 = creator1.factory();
System.out.println("----------------------------");
creator2 = new ConcreteCreator2();
prod2 = creator2.factory();
}
}
抽象工厂:
//定义不同的产品之间的一定具备的标准,用interface实现
//其中的method()方法可看作提取出不同产品的共性,如手机都有类似的功能
interface IProductA{
public void method();
} interface IProductB{
public void method();
} //实现了产品标准实现的一系列具体产品
//由于已经设计好A1由厂商1生产,故以下输出代码有“厂商x”
class ProductA1 implements IProductA{
public void method() {
System.out.println("厂商1 生产ProductA1 ...");
}
} class ProductA2 implements IProductA{
public void method() {
System.out.println("厂商2 生产ProductA2 ...");
}
} class ProductB1 implements IProductB{
public void method() {
System.out.println("厂商1 生产ProductB1 ...");
}
} class ProductB2 implements IProductB{
public void method() {
System.out.println("厂商2 生产ProductB2 ...");
}
} //每一种牌子的产品生产工厂,即不同的厂商负责自己牌子产品的生产
abstract class Factory1{
abstract IProductA getProductA1();
abstract IProductB getProductB1();
} abstract class Factory2{
abstract IProductA getProductA2();
abstract IProductB getProductB2();
} //具体的工厂用来生产相关的产品
class ConcreteFactory1 extends Factory1{
public IProductA getProductA1() {
return new ProductA1();
}
public IProductB getProductB1() {
return new ProductB1();
}
} class ConcreteFactoryB extends Factory2{
public IProductA getProductA2() {
return new ProductA2();
}
public IProductB getProductB2() {
return new ProductB2();
}
} //测试类
public class Client {
public static void main(String[] args) {
//厂商1负责生产产品A1、B1
Factory1 factory1 = new ConcreteFactory1();
IProductA productA1 = factory1.getProductA1();
IProductB productB1 = factory1.getProductB1(); productA1.method();
productB1.method(); //厂商2负责生产产品A2、B2
Factory2 factory2 = new ConcreteFactoryB();
IProductA productA2 = factory2.getProductA2();
IProductB productB2 = factory2.getProductB2(); productA2.method();
productB2.method();
}
}
4. 应用场景
工厂方法:
在以下情况下,适用于工厂方法模式:
(1) 当一个类不知道它所必须创建的对象的类的时候。
(2) 当一个类希望由它的子类来指定它所创建的对象的时候。
(3) 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
抽象工厂:
(1) 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
(2) 这个系统有多于一个的产品族,而系统只消费其中某一产品族。
(3) 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
(4) 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
设计模式3---工厂模式(Factory Pattern简单工厂、工厂方法、抽象工厂)的更多相关文章
- python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)
十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...
- 设计模式 - 工厂模式(factory pattern) 具体解释
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u012515223/article/details/27081511 工厂模式(factory pa ...
- 工厂模式(factory pattern)
工厂模式主要用来封装对象的创建,有3种分类:简单工厂(simple factory).工厂方法(factory method).抽象工厂(abstract factory). 简单工厂包括3种组成元素 ...
- 23种设计模式--工厂模式-Factory Pattern
一.工厂模式的介绍 工厂模式让我们相到的就是工厂,那么生活中的工厂是生产产品的,在代码中的工厂是生产实例的,在直白一点就是生产实例的类,代码中我们常用new关键字,那么这个new出来的实例 ...
- 【设计模式】工厂模式 Factory Pattern
1)简单工厂(不是模式) 简单工厂只是一种变成习惯,并非23种设计模式之一. 简单工厂提供将实例话那种类型留给运行时判断,而非编译时指定.简单工厂模式就是由一个工厂类根据传入的参数决定创建出哪一个类的 ...
- JAVA设计模式之工厂模式—Factory Pattern
1.工厂模式简介 工厂模式用于对象的创建,使得客户从具体的产品对象中被解耦. 2.工厂模式分类 这里以制造coffee的例子开始工厂模式设计之旅. 我们知道coffee只是一种泛举,在点购咖啡时需要指 ...
- 创建型模式篇(工厂模式Factory Pattern)
一.工厂模式(Factory Pattern) 1.定义: 在软件系统,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口.提供一种封 ...
- 工厂模式(factory pattern) ------创造型模式
创建型模式 简单工厂模式的缺点是: 当我们引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,需要修改工厂类的方法,违反了“开闭原则”. 工厂模式提供了一个抽象工厂接口来声明抽象工厂方 ...
- java_设计模式_工厂模式_Factory Pattern(2016-08-04)
工厂模式主要是为创建对象提供了接口.工厂模式按照<Java与模式>中的提法分为三类: (1)简单工厂(Simple Factory)模式,又称静态工厂方法模式(Static Factory ...
随机推荐
- angularJs中的发送请求例子
$http({ //发送请求 url: 'http://localhost:8080/teacher/api/login', method: 'post', data: obj }) .success ...
- Shachar Fleishma的论文,做点云重建的几篇论文都不错
http://www.sci.utah.edu/~shachar/ 几篇论文都不错,但貌似05年之后就没有什么动作了.
- Rhythmk 一步一步学 JAVA(4):Spring MVC -之拦截器
1.实现拦截器类(myInterceptor): package com.rhythmk.Interceptor; import javax.servlet.http.HttpServletReque ...
- Vue2不使用Vuex如何实现兄弟组件间的通信
在一些正规的大型项目的企业级开发过程中我们一般会引入Vuex来对Vue所有组件进行状态管理,可以轻松实现各组件间的通信.但是有时候做做自己的小项目,没有必要使用Vuex时,如何简单的实现组件间的通信? ...
- Elasticsearch-2.4.3的单节点安装(多种方式图文详解)
前提: Elasticsearch-2.4.3的下载(图文详解) 1.新建es安装目录 [root@djt002 local]# mkdir elasticsearch [root@djt002 lo ...
- 收集了一些iOS技术面试题
1.Difference between shallow copy and deep copy? 浅复制和深复制的区别? 答案:浅层复制:只复制指向对象的指针,而不复制引用对象本身. 深层复制:复制 ...
- 自定义javascript日历控件
Web页中的日历一般离不开表格,通常都使用表格装载指定月的日期等信息.所以,要编写JS日历,首先必须解决的问题是表格的行与列问题.列是固定的,七列,因为一周有七天.行需要动态计算,因为,每一个月的第一 ...
- go_指针
值传递:相当于在内存中拷贝一分变量出来,拷贝变量的改变对原变量不影响 引用传递:直接引用内存中的变量,会被改变 c,c++值传递和引用传递都有 Java,python多用引用传递 go语言指针简单之处 ...
- 读取properties文件并获取属性值
1.Properties与ResourceBundle 两个类都可以读取属性文件中以key/value形式存储的键值对,ResourceBundle读取属性文件时操作相对简单. 2.Propertie ...
- SpringCloud04 服务配置中心、消息总线、远程配置动态刷新
1 环境说明 JDK:1.8 MAVENT:3.5 SpringBoot:2.0.5.RELEASE SpringCloud:Finchley.SR1 2 创建服务注册中心(Eureka服务端) 说明 ...