Java设计模式—工厂方法模式&抽象工厂模式
工厂方法模式与抽象工厂模式都是设计模式中重要而且常见的模式。
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
通用类图如下:
在工厂方法模式中,抽象产品类Product负责定义产品的共性,实现对事物最抽象的定义;Creator为抽象创建
类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的。
工厂方法模式的扩展方式有很多种,下边是工厂方法模式一个比较实用的源代码:
抽象产品类:
public abstract class Product {
//产品类的公共方法
public void method1(){
//业务逻辑处理
}
//抽象方法
public abstract void method2();
}
具体的产品类可以有多个,都继承于抽象产品类。
public class ConcreteProduct1 extends Product {
public void method2() {
//业务逻辑处理
}
}
public class ConcreteProduct2 extends Product {
public void method2() {
//业务逻辑处理
}
}
抽象工厂类负责定义产品对象的产生:
public abstract class Creator {
/*
* 创建一个产品对象,其输入参数类型可以自行设置
* 通常为String、Enum、Class等,当然也可以为空
*/
public abstract <T extends Product> T createProduct(Class<T> c);
}
具体如何产生一个产品的对象,是由具体的工厂类实现的:
public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c){
Product product=null;
try {
product = (Product)Class.forName(c.getName()).newInstance();
} catch (Exception e) {
//异常处理
}
return (T)product;
}
}
场景类如下所示:
public class Client {
public static void main(String[] args) {
Creator creator = new ConcreteCreator();
Product product = creator.createProduct(ConcreteProduct1.class);
/*
* 继续业务处理
*/
}
}
该通用代码是一个比较实用、易扩展的框架。
工厂方法模式的优点:
(1)良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要
知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合。
(2)工厂方法模式的扩展性非常优秀。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,
就可以完成“拥抱变化”。
(3)屏蔽产品类。这一特点非常重要,产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,
只要接口保持不变,系统中的上层模块就不要发生变化。因为产品类的实例化工作是由工厂类负责的,一个产品对象
具体由哪一个产品生成是由工厂类决定的。
使用场景:
首先,工厂方法模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重地考
虑是否要增加一个工厂类进行管理,增加代码的复杂度。
工厂方法模式的扩展:
(1)简单工厂模式
当一个模块只需要一个工工厂类时,我们可以将抽象工厂类kill掉,然后将具体工厂类中制造产品的方法前面加static
关键字,则,工厂方法模式就变为了简单工厂模式。
该模式是工厂方法模式的弱化,因为简单,所以称为简单工厂模式(Simple Factory Pattern),也叫做静态工
厂模式。在实际项目中,采用该方法的案例还是比较多的,其缺点是工厂类的扩展比较困难,不符合开闭原则,但它
仍然是一个非常实用的设计模式。
(2)多工厂模式
当遇到一个复杂的项目,初始化一个对象很费事的时候,我们可以使用多工厂模式,即一个工厂只生产特定的某种产
品,实现了单一职责。
每一个产品类都对应了一个创建类,好处就是创建类的职责清晰,而且结构简单,但是给可扩展性和可维护性带
来了一定的影响。为什么这么说呢?如果要扩展一个产品类,就需要建立一个相应的工厂类,这样就增加了扩展的难
度。因为工厂类和产品类的数量相同,维护时需要考虑两个对象之间的关系。
当然,在复杂的应用中一般采用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流,协调类
的作用是封装子工厂类,对高层模块提供统一的访问接口。
抽象工厂模式
抽象工厂模式是一种比较常用的模式。
其定义如下:
为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。
通用类图如下:
抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的
对象是一种非常好的解决方式。我们来看看抽象工厂的通用源代码,首先有两个互相影响的产品线(也叫做产族),
例如制造汽车的左侧门和右侧门,这两个应该是数量相等的——两个对象之间的约束,每个型号的车门都是不
一样的,这是产品等级结构约束的,我们先看看两个产品族的类图,如下所示:
注意类图上的圈圈、框框相对应,两个抽象的产品类可以有关系,例如共同继承或实现一个抽象类或接口。
通用源代码如下:
//抽象产品类
public abstract class AbstractProduct A {
//每个产品共有的方法
public void shareMethod(){
}
//每个产品相同方法,不同实现
public abstract void doSomething();
}
产品A1的实现类
public class ProductA1 extends AbstractProductA {
public void doSomething() {
System.out.println("产品A1的实现方法");
}
}
产品A2的实现类
public class ProductA2 extends AbstractProductA {
public void doSomething() {
System.out.println("产品A2的实现方法");
}
}
产品B与此类似,不再赘述。
抽象工厂类
public abstract class AbstractCreator {
//创建A产品家族
public abstract AbstractProductA createProductA();
//创建B产品家族
public abstract AbstractProductB createProductB();
}
注意:有N个产品族,在抽象工厂类中就应该有N个创建方法。
产品等级1的实现类
public class Creator1 extends AbstractCreator {
//只生产产品等级为1的A产品
public Abstract ProductA createProductA() {
return new ProductA1();
}
//只生产产品等级为1的B产品
public AbstractProductB createProductB() {
return new ProductB1();
}
}
产品等级2的实现类
public class Creator2 extends AbstractCreator {
//只生产产品等级为2的A产品
public AbstractProductA createProductA() {
return new ProductA2();
}
//只生产产品等级为2的B产品
public AbstractProductB createProductB() {
return new ProductB2();
}
}
注意:M个实现工厂类,在每个实现工厂中,实现不同产品族的生产任务。
场景类如下:
public class Client {
public static void main(String[] args) {
//定义出两个工厂
Abstract Creator creator1 = new Creator1();
Abstract Creator creator2 = new Creator2();
//产生A1对象
AbstractProductA a1 = creator1.createProductA();
//产生A2对象
AbstractProductA a2 = creator2.createProductA();
//产生B1对象
AbstractProductB b1 = creator1.createProductB();
//产生B2对象
AbstractProductB b2 = creator2.createProductB();
/*
* 然后在这里就可以为所欲为了...
*/
}
}
抽象工厂模式的优点:
● 封装性。
每个产品的实现类不是高层模块要关心的,它要关心的是什么?是接口,是抽象,它不关心对象是如何创建出
来,这由谁负责呢?工厂类,只要知道工厂类是谁,我就能创建出一个需要的对象,省时省力,优秀设计就应该如
此。
● 产品族内的约束为非公开状态。
缺点:
抽象工厂模式的最大缺点就是产品族扩展非常困难,为什么这么说呢?我们以通用代码为例,如果要增加一个产
品C,也就是说产品家族由原来的2个增加到3个,看看我们的程序有多大改动吧!抽象类AbstractCreator要增加一个
方法createProductC(),然后两个实现类都要修改,想想看,这严重违反了开闭原则,而且我们一直说明抽象类和接
口是一个契约。改变契约,所有与契约有关系的代码都要修改,那么这段代码叫什么?叫“有毒代码”,——只要与这
段代码有关系,就可能产生侵害的危险!
两种设计模式的区别:
区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工
厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,
抽象工厂模式针对的是面向多个产品等级结构的。
工厂方法模式与抽象工厂模式对比:
工厂方法模式 |
抽象工厂模式 |
针对的是一个产品等级结构 | 针对的是面向多个产品等级结构 |
一个抽象产品类 | 多个抽象产品类 |
可以派生出多个具体产品类 | 每个抽象产品类可以派生出多个具体产品类 |
一个抽象工厂类,可以派生出多个具体工厂类 | 一个抽象工厂类,可以派生出多个具体工厂类 |
每个具体工厂类只能创建一个具体产品类的实例 | 每个具体工厂类可以创建多个具体产品类的实例 |
如果对你有帮助,记得点赞哦~
Java设计模式—工厂方法模式&抽象工厂模式的更多相关文章
- Java设计模式---工厂模式(简单工厂、工厂方法、抽象工厂)
工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类.工厂模式的形态工厂模式主要用一下几种形态:1:简单工厂(Simple Factory).2:工厂方法(Factory M ...
- Java设计模式(三) 抽象工厂模式
原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...
- 设计模式3---工厂模式(Factory Pattern简单工厂、工厂方法、抽象工厂)
工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类.工厂模式的形态工厂模式主要用一下几种形态:1:简单工厂(Simple Factory).2:工厂方法(Factory M ...
- 设计模式(Python)-简单工厂,工厂方法和抽象工厂模式
本系列文章是希望将软件项目中最常见的设计模式用通俗易懂的语言来讲解清楚,并通过Python来实现,每个设计模式都是围绕如下三个问题: 为什么?即为什么要使用这个设计模式,在使用这个模式之前存在什么样的 ...
- Java设计模式之简单工厂、工厂方法和抽象工厂
在前面的学习中(参见前面的博客),我们学到了很多OO原则: 封装变化 多用组合,少用继承 针对接口/超类编程,不针对实现编程 松耦合 开闭原则 让我们从一个简单的类开始,看看如何将之改造成符合OO原则 ...
- c# 设计模式 之:简单工厂、工厂方法、抽象工厂之小结、区别
很多时候,我发现这三种设计模式难以区分,常常会张冠李戴闹了笑话.很有必要深入总结一下三种设计模式的特点.相同之处和不同之处. 1 本质 三个设计模式名字中都含有“工厂”二字,其含义是使用工厂(一个或一 ...
- 简单工厂 VS 工厂方法 VS 抽象工厂
说到设计模式.自然少不了简单工厂模式.工厂方法和抽象工厂这三姐妹. 它们之间可谓是各有所长,术业专攻啊!这篇博客来简单的梳理一下三者之间的关系. 那么工厂又是什么意思呢?结合三者的特点,我觉得能够这样 ...
- Java设计模式(二)抽象工厂模式
一.场景描述 接<Java设计模式(一)工厂模式>https://www.cnblogs.com/mahongbiao/p/8618970.html 工厂模式有一缺点,就是破坏了类的封闭性 ...
- Java设计模式学习笔记(四) 抽象工厂模式
前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...
- Java设计模式:Abstract Factory(抽象工厂)模式
概念定义 抽象工厂(Abstract Factory)模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 抽象工厂模式中,系统的产品有多于一个的产品族(一个产品族里定义多个产品) ...
随机推荐
- Codeforces Round #555 (Div. 3) A B C1(很水的题目)
A. Reachable Numbers 题意:设f(x)为 x+1 这个数去掉后缀0的数,现在给出n,问经过无数次这种变换后,最多能得到多少个不同的数. 代码 #include<cstdio& ...
- Flutter视图基础简介--Widget、Element、RenderObject
前言:Flutter官方文档里的一句话:you build your UI out of widgets(使用Flutter开发UI界面时,都是使用Widget),然而,Widget并不是我们真正看到 ...
- Map集合的四种遍历方式(转载)
import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class TestMap { pu ...
- VS2015 release模式下进行debug调试
有时候软件发布,又不得不调试其中的某个dll模块, 这时候就需要在发布的release版本的软件中来调试其中的dll模块了. vs2015设置: 1.Release模式下右键工作属性,选择C/C++, ...
- guava学习:guava集合类型-Bimap
学习guava让我惊喜的第二个接口就是:Bimap BiMap是一种特殊的映射其保持映射,同时确保没有重复的值是存在于该映射和一个值可以安全地用于获取键背面的倒数映射. 最近开发过程中,经常会有这种根 ...
- 在WPF中如何使用RelativeSource绑定
在WPF绑定的时候,指定绑定源时,有一种办法是使用RelativeSource. 这种办法的意思是指当前元素和绑定源的位置关系. 第一种关系: Self 举一个最简单的例子:在一个StackPanel ...
- WPF EventAggregator(基于EventAggregator的事件发布及订阅)
一.EventAggregator简介 EventAggregator是Prism中专门处理ViewModel与ViewModel之间事件传递的类对象,它提供了针对事件的发布方法和订阅方法,所以可以非 ...
- WPF中使用RenderTransformOrigin来控制动画的起点
Render :渲染:Transform:动画:Origin:起点 RenderTransformOrigin:渲染动画的起点 取值为一个坐标的形式 取值范围: 0,0 到 1,1 0,0:表示左上 ...
- JS中深拷贝数组、对象、对象数组方法
我们在JS程序中需要进行频繁的变量赋值运算,对于字符串.布尔值等可直接使用赋值运算符 “=” 即可,但是对于数组.对象.对象数组的拷贝,我们需要理解更多的内容. 首先,我们需要了解JS的浅拷贝与深拷贝 ...
- Eclipse项目红感叹号
原因:显示红色感叹号是因为jar包的路径不对 解决:在项目上右击Build Path -> Configure Build Paht...(或Propertise->Java Build ...