当前位置: 首页 > news >正文

【设计模式】工厂方法模式详解

在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目目的;所以说,工厂模式最大的优点就是解耦。

简单工厂(不属于GOF23种设计模式之一):

不是一种设计模式,更像是一种编码习惯

要学习工厂方法,必须先了解什么是简单工厂

结构
  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品:实现或者继承抽象产品的子类(即产品本身)。
  • 具体工厂:提供了创建产品的方法,调用者通过该方法来进行产品的创建
优点

封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。

缺点

增加新产品时还是需要修改工厂类的代码,违背了“开闭原则"

// 定义一个接口或抽象类
interface Shape {void draw();
}// 定义具体的产品类
class Circle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a circle...");}
}class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a rectangle...");}
}// 定义简单工厂类
class ShapeFactory {// 工厂方法,根据输入参数决定创建哪种产品public static Shape getShape(String type) {if ("circle".equalsIgnoreCase(type)) {return new Circle();} else if ("rectangle".equalsIgnoreCase(type)) {return new Rectangle();} else {throw new IllegalArgumentException("Invalid shape type: " + type);}}
}// 客户端代码
public class Client {public static void main(String[] args) {// 使用简单工厂创建不同形状的对象Shape circle = ShapeFactory.getShape("circle");circle.draw();  // 输出: Drawing a circle...Shape rectangle = ShapeFactory.getShape("rectangle");rectangle.draw();  // 输出: Drawing a rectangle...// 尝试创建无效类型try {Shape invalidShape = ShapeFactory.getShape("triangle");} catch (IllegalArgumentException e) {System.out.println(e.getMessage());}}
}

在这个例子中,ShapeFactory是简单工厂,它负责根据传入的字符串类型创建相应的形状对象。客户端代码只需调用工厂方法,不需要关心具体的创建过程。

工厂方法

针对上例中的缺点,使用工厂方法模式就可以完美的解决完全遵循开闭原则。

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。

结构
  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂(Concreteractory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct实现了抽象产品角色所定义的接口,由县体工厂来创建,它同县体工厂之间一一对应

将简单工厂模式升级为工厂方法模式,我们需要将创建具体产品的逻辑移到每个具体工厂类中,而不是集中在一个静态工厂方法中。以下是将简单工厂模式转换为工厂方法模式的Java代码示例:

// 定义一个接口或抽象类
interface Shape {void draw();
}// 定义具体的产品类
class Circle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a circle...");}
}class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Drawing a rectangle...");}
}// 定义抽象工厂类
abstract class ShapeFactory {// 抽象工厂方法,由子类实现以创建具体产品public abstract Shape getShape();
}// 定义具体工厂类
class CircleFactory extends ShapeFactory {@Overridepublic Shape getShape() {return new Circle();}
}class RectangleFactory extends ShapeFactory {@Overridepublic Shape getShape() {return new Rectangle();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 使用工厂方法模式创建不同形状的对象ShapeFactory circleFactory = new CircleFactory();Shape circle = circleFactory.getShape();circle.draw();  // 输出: Drawing a circle...ShapeFactory rectangleFactory = new RectangleFactory();Shape rectangle = rectangleFactory.getShape();rectangle.draw();  // 输出: Drawing a rectangle...// 如果需要添加更多形状,只需要创建更多的具体工厂类即可,这里不再演示创建三角形的工厂类}
}

在这个工厂方法模式的示例中,我们创建了一个抽象工厂类ShapeFactory,并在其中定义了抽象方法getShape()。然后,我们分别为每种形状创建了具体工厂类(如CircleFactory和RectangleFactory),并在这些类中实现创建相应形状对象的逻辑。客户端代码现在可以根据需求实例化不同的具体工厂类来创建所需形状对象。

优点
  1. 用户只需要知道具体工厂的名称就可得到所要的产品无须知道产品的具体创建过程
  2. 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则
缺点

每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

典型案例 Collection.iterator
List<String> list = Arrays.asList("a","b","c","d");
Iterator<String> iterator = list.iterator();
// ArrayList部分源码
public interface AbstractList<E> extends AbstractCollection<E> implements List<E>  {// Iteratorspublic Iterator<E> iterator() {return new Itr();}public ListIterator<E> listIterator() {return listIterator(0);}public ListIterator<E> listIterator(final int index) {rangeCheckForAdd(index);return new ListItr(index);}private class Itr implements Iterator<E>{...}private class ListItr extends Itr implements ListIterator<E>{...}}
// Collection 部分源码
public interface Collection<E> extends Iterable<E> {Iterator<E> iterator();
}
// Interator部分源码
public interface Iterator<E> {boolean hasNext();E next();
}

在Collection中定义了Iterator的抽象方法,而ArrayList又继承Collection,并在类中重写了Interator的方法。
也就是说ArrayList类是在工厂类中创建了Iterator 和ListIterator 的产品。即:

  • Collection接口是抽象工厂类,
  • ArrayList是具体的工厂类;
  • Iterator接口是抽象商品类,
  • ArrayList类中的Iter和ListItr是具体的商品类。
    在具体的工厂类中iterator()方法是创建具体的商品类对象。

相关文章:

  • 输出1到10的阶乘--C语言
  • linux之自主shell编写
  • 【MATLAB源码-第22期】基于matlab的手动实现的(未调用内置函数)CRC循环码编码译码仿真。
  • 关于MD5加密
  • uniapp实现列表动态添加
  • 软考105-上午题-【结构化开发】-系统文档
  • uniapp保留两位小数,整数后面加.00
  • window下迁移SVN仓库到新的windows服务器
  • 支付后打开半屏小程序能力的相关调整通知
  • C语言优先级浅记
  • node.js学习(2)
  • .Net Web窗口页属性
  • go |struct embedding、generics、goroutine
  • Clip Converter - 视频在线下载方法
  • java多线程中的阻塞队列
  • JavaScript-如何实现克隆(clone)函数
  • 收藏网友的 源程序下载网
  • $translatePartialLoader加载失败及解决方式
  • [case10]使用RSQL实现端到端的动态查询
  • 11111111
  • C++11: atomic 头文件
  • E-HPC支持多队列管理和自动伸缩
  • gitlab-ci配置详解(一)
  • Git的一些常用操作
  • Gradle 5.0 正式版发布
  • Java IO学习笔记一
  • JavaScript对象详解
  • JavaScript异步流程控制的前世今生
  • MySQL数据库运维之数据恢复
  • Object.assign方法不能实现深复制
  • Objective-C 中关联引用的概念
  • Python socket服务器端、客户端传送信息
  • sublime配置文件
  • 数据科学 第 3 章 11 字符串处理
  • 网页视频流m3u8/ts视频下载
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • const的用法,特别是用在函数前面与后面的区别
  • 阿里云移动端播放器高级功能介绍
  • 如何在招聘中考核.NET架构师
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #if 1...#endif
  • $forceUpdate()函数
  • (编译到47%失败)to be deleted
  • (第27天)Oracle 数据泵转换分区表
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (十一)手动添加用户和文件的特殊权限
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)详解PHP处理密码的几种方式
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .Net Attribute详解(上)-Attribute本质以及一个简单示例
  • .NET CLR Hosting 简介