创建型模式之:
- 单例模式
工厂模式
- 构造者模式
- 克隆模式
1.工厂模式产生的原因?
工厂模式是一种创建型设计模式,其目的是封装对象的创建过程,以便在整个系统中灵活地创建对象。工厂模式有多种形式,包括简单工厂模式
、工厂方法模式
和抽象工厂模式
。
1. 简单工厂模式的起源:
简单工厂模式是工厂模式中最基本的形式。它的起源可以追溯到基于流水线生产的工业时代。在这个时代,产品的生产被分为多个步骤,每个步骤由专门的工人或机器完成。这种分工使得生产过程更加高效,每个工人或机器专注于自己的任务。
类比到软件设计中,简单工厂模式的思想是将对象的创建过程封装在一个工厂类中,客户端只需要通过工厂类获取所需的对象,而不需要关心对象的创建细节。这种方式使得系统更加灵活,客户端与具体产品的实现解耦。
2.有哪些工厂模式?
前面了解了工厂模式主要分为3种,那举个例子说明下他们的区别:假设我们有一个形状(Shape
)的层次结构,包括圆形(Circle
)和矩形
2.1工厂模式
在工厂模式中,有一个单一的工厂负责创建不同类型的产品
// 形状接口
interface Shape {
void draw();
}
// 圆形实现
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Draw a Circle");
}
}
// 矩形实现
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Draw a Rectangle");
}
}
// 形状工厂
class ShapeFactory {
public Shape createShape(String type) {
if ("Circle".equalsIgnoreCase(type)) {
return new Circle();
} else if ("Rectangle".equalsIgnoreCase(type)) {
return new Rectangle();
}
return null;
}
}
使用工厂模式:
public class Client {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
Shape circle = shapeFactory.createShape("Circle");
circle.draw(); // Draw a Circle
Shape rectangle = shapeFactory.createShape("Rectangle");
rectangle.draw(); // Draw a Rectangle
}
}
2.2工厂方法模式
在工厂方法模式中,每个具体的产品有对应的工厂类。
// 形状工厂接口
interface ShapeFactory {
Shape createShape();
}
// 圆形工厂
class CircleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Circle();
}
}
// 矩形工厂
class RectangleFactory implements ShapeFactory {
@Override
public Shape createShape() {
return new Rectangle();
}
}
使用工厂方法模式:
public class Client {
public static void main(String[] args) {
ShapeFactory circleFactory = new CircleFactory();
Shape circle = circleFactory.createShape();
circle.draw(); // Draw a Circle
ShapeFactory rectangleFactory = new RectangleFactory();
Shape rectangle = rectangleFactory.createShape();
rectangle.draw(); // Draw a Rectangle
}
}
2.3抽象工厂模式
在抽象工厂模式中,有一个抽象工厂接口,每个具体的产品族(例如形状和颜色)都有对应的具体工厂类。
// 形状接口
interface Shape {
void draw();
}
// 圆形实现
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Draw a Circle");
}
}
// 矩形实现
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Draw a Rectangle");
}
}
// 颜色接口
interface Color {
void fill();
}
// 红色实现
class Red implements Color {
@Override
public void fill() {
System.out.println("Fill with Red");
}
}
// 蓝色实现
class Blue implements Color {
@Override
public void fill() {
System.out.println("Fill with Blue");
}
}
// 抽象工厂接口
interface AbstractFactory {
Shape createShape();
Color createColor();
}
// 具体形状工厂
class ShapeFactory implements AbstractFactory {
@Override
public Shape createShape() {
return new Circle();
}
@Override
public Color createColor() {
return new Red();
}
}
// 具体形状工厂
class RectangleFactory implements AbstractFactory {
@Override
public Shape createShape() {
return new Rectangle();
}
@Override
public Color createColor() {
return new Blue();
}
}
使用抽象工厂模式:
public class Client {
public static void main(String[] args) {
AbstractFactory shapeFactory = new ShapeFactory();
Shape circle = shapeFactory.createShape();
circle.draw(); // Draw a Circle
Color red = shapeFactory.createColor();
red.fill(); // Fill with Red
AbstractFactory rectangleFactory = new RectangleFactory();
Shape rectangle = rectangleFactory.createShape();
rectangle.draw(); // Draw a Rectangle
Color blue = rectangleFactory.createColor();
blue.fill(); // Fill with Blue
}
}
工厂模式
通过一个单一的工厂类
创建产品。工厂方法模式
每个产品有对应的工厂类
,更符合开闭原则。抽象工厂模式
引入了产品族的概念,每个产品族有对应的抽象工厂
,更适用于创建一组相关的产品。
可以看出来工厂模式,是针对不同打的复杂对做了区分,在开发中我们需要根据不同的使用场景来选择不同的工厂模式。
3.怎么用工厂模式?
怎么使用工厂模式,其实更重要的一点是知道什么情况下使用工厂模式,设计模式的难点并不是你背不过23中设计模式的名字,或者你不知道他们代码怎么写,而是大多数人不知道什么时候改用设计模式。使用工厂模式的标准是什么呢?
封装变化
:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。代码复用
:创建代码抽离到独立的工厂类之后可以复用。隔离复杂性
:封装复杂的创建逻辑,调用者无需了解如何创建对象。控制复杂度
:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。如果创建对象的逻辑比较复杂,可能涉及到多个步骤、条件判断或者依赖关系,这时候使用工厂模式可以将创建对象的逻辑封装在工厂类中,使客户端代码更加简洁。
4.工厂模式有什么缺点?
- 类的数量增加: 引入工厂模式会增加类的数量,因为每个具体产品都需要对应一个具体工厂类。这可能导致类的数量庞大,使得项目结构变得复杂,简单的小需求就不需要使用工厂模式了。
- 违反开闭原则: 如果需要添加新的产品类型,除了新增产品类外,还需要修改对应的工厂类。这违反了开闭原则,即对扩展开放,对修改关闭。
- 抽象层次的过度: 如果产品族中的产品种类很多,可能会导致抽象工厂接口的抽象层次过度复杂,不易理解和维护。
- 静态工厂方法无法被子类覆盖: 在使用静态工厂方法时,它们通常不能被子类覆盖,因为静态方法是属于类而不是对象的。
- 与依赖注入的冲突: 在某些情况下,工厂模式可能与依赖注入的实践产生冲突。依赖注入通常使用框架来管理对象的创建和注入,而工厂模式可能引入了额外的工厂类。
5.知识扩展(依赖注入)
工厂模式的缺陷就是跟依赖注入产生冲突。那么为什么会产生冲突呢?
5.1 工厂模式和DI容器的区别
- DI 容器底层最基本的设计思路就是基于工厂模式的。DI 容器相当于一个大的工厂 类,负责在程序启动的时候,根据配置(要创建哪些类对象,每个类对象的创建需要依赖哪 些其他类对象)事先创建好对象。当应用程序需要使用某个类对象的时候,直接从容器中获 取即可。正是因为它持有一堆对象,所以这个框架才被称为“容器”
- DI 容器相对于我们上节课讲的工厂模式的例子来说,它处理的是更大的对象创建工程。上 节课讲的工厂模式中,一个工厂类只负责某个类对象或者某一组相关类对象(继承自同一抽 象类或者接口的子类)的创建,而 DI 容器负责的是整个应用中所有类对象的创建。
- DI 容器负责的事情要比单纯的工厂模式要多。比如,它还包括配置的解析、对象生命周期的管理。