23种设计模式之工厂模式(Factory Pattern)
创建型设计模式
意图: 隐藏复杂对象的创建逻辑,统一管理复杂对象的生成。
这里强调复杂对象是因为,简单的对象生成完全不需要通过工厂类来生成。直接通过简单的new即可。
过度的滥用设计模式会造成系统的臃肿
优点:
- 屏蔽产品的实现,调用者只关心产品的接口
- 扩展性高,如果想增加一个产品,只要拓展改变工厂即可
缺点:
1. 每次增加产品时,都需要增加一个类和对象的实现工厂,系统中的类会成倍的增加,造成系统过于庞大。
1. 简单工厂模式
1.1 简单工厂中包含的角色
- 工厂类 (提供一个返回抽象类类型的方法,方法参数接收具体类的类型,根据类型返回具体类)
- 抽象类接口
- 具体类(实现抽象类接口)
1.2 简单工厂的代码实现
//简单工厂
public interface Shape {
void draw();
}
public class ShapeImplOne implements Shape {
@Override
public void draw() {
System.out.println("shapeImplOne run");
}
}
public class ShapeImplTwo implements Shape {
@Override
public void draw() {
System.out.println("shapeImplTwo run");
}
}
public class ShapeFactory {
public static Shape getShape(String shape){
if (StringUtils.isEmpty(shape)){
return null;
}
if (shape.equals("shapeImplOne")){
return new ShapeImplOne();
}else if (shape.equals("shapeImplTwo")){
return new ShapeImplTwo();
}
return null;
}
}
public class ShapeFactoryTest {
public static void main(String[] args) {
Shape shapeImplOne = ShapeFactory.getShape("shapeImplOne");
shapeImplOne.draw();
Shape shapeImplTwo = ShapeFactory.getShape("shapeImplTwo");
shapeImplTwo.draw();
Shape shapeImpl = ShapeFactory.getShape("");
shapeImpl.draw();
}
}
1.3 简单工厂的优缺点分析
简单工厂由于使用if else 判断,增加一个产品时,不需要增加对象的实现工厂,在else if 里面 可以直接创建。不会造成系统中类过于臃肿的情况。由于简单工厂每次新增一个产品子项,都需要在工厂类中去修改代码,违背了开闭原则。
2. 抽象工厂模式
围绕一个超级工厂建造其他的工厂,该工厂又称为其他工厂的工厂。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显示的指定他们的类,每个生成的工厂都能按照那工厂模式提供对象。
2.1 抽象工厂中包含的角色
- 抽象工厂
- 抽象工厂的实现类
- 抽象产品
- 抽象产品的实现类
2.2 抽象工厂的简单代码实现
//抽象工厂
public interface Shape {
void draw();
}
public class ShapeImplOne implements Shape {
@Override
public void draw() {
System.out.println("shapeImplOne run");
}
}
public class ShapeImplTwo implements Shape {
@Override
public void draw() {
System.out.println("shapeImplTwo run");
}
}
public interface ShapeFactory {
Shape getShape();
}
public class ShapeFactoryA implement ShapeFactory {
@Override
public Shape getShape() {
return new ShapeImplOne();
}
}
public class ShapeFactoryB implement ShapeFactory {
@Override
public Shape getShape() {
return new ShapeImplTwo();
}
}
public class ShapeFactoryTest {
public static void main(String[] args) {
ShapeFactory factory = new ShapeFactoryB();
Shape shapeB = factory.getShape();
shapeB.draw();
}
}
2.3 抽象工厂的优缺点分析
抽象工厂和工厂方法实际上是同一种东西,抽象工厂是工厂方法的延续。解决了简单工厂违背开闭原则的问题。但是新增产品时,容易造成系统中类过于臃肿的情况
3. 抽象工厂的案例分析
假设我们现在有一个需求,形状有圆形和方形,在形状的基础上又有红色和蓝色。
3.1 实现方式一:(颜色抽象工厂)
3.1.1 代码实现
public interface Shape {
void draw();
}
public abstract class Circle implements Shape {
}
public abstract class Rectangle implements Shape {
}
public class RedCircle extends Circle {
@Override
public void draw() {
System.out.println("Red Circle");
}
}
public class BuleCircle extends Circle {
@Override
public void draw() {
System.out.println("Bule Circle");
}
}
public class RedRectangle extends Rectangle {
@Override
public void draw() {
System.out.println("Red Rectangle");
}
}
public class BuleRectangle extends Rectangle {
@Override
public void draw() {
System.out.println("Bule Rectangle");
}
}
public interface ShapeFactory {
Shape getCircle();
Shape getRectangle();
}
public class RedShapeFactory implements ShapeFactory {
@Override
public Shape getCircle() {
return new RedCircle();
}
@Override
public Shape getRectangle() {
return new RedRectangle();
}
}
public class BuleShapeFactory implements ShapeFactory {
@Override
public Shape getCircle() {
return new BuleCircle();
}
@Override
public Shape getRectangle() {
return new BuleRectangle();
}
}
public class Test{
public static void main(String[] args) {
BuleShapeFactory shapeFactory = new BuleShapeFactory();
Shape shape = shapeFactory.getRectangle();
shape.draw();
}
}
3.2 实现方式二:(形状抽象工厂)
3.2.1 代码实现
public interface Shape {
void draw();
}
public abstract class RedShape implements Shape {
}
public abstract class BuleShape implements Shape {
}
public class RedCircle extends RedShape {
@Override
public void draw() {
System.out.println("Red Circle");
}
}
public class RedRectangle extends RedShape {
@Override
public void draw() {
System.out.println("Red Rectangle");
}
}
public class BuleCircle extends BuleShape {
@Override
public void draw() {
System.out.println("Bule Circle");
}
}
public class BuleRectangle extends BuleShape {
@Override
public void draw() {
System.out.println("Bule Rectangle");
}
}
public interface ColorFactory {
Shape getRed();
Shape getBule();
}
public class CircleColorFactory implements ColorFactory {
@Override
public Shape getRed() {
return new RedCircle();
}
@Override
public Shape getBule() {
return new BuleCircle();
}
}
public class RectangleColorFactory implements ColorFactory {
@Override
public Shape getRed() {
return new RedRectangle();
}
@Override
public Shape getBule() {
return new BuleRectangle();
}
}
public class Test{
public static void main(String[] args) {
ColorFactory colorFactory = new CircleColorFactory();
Shape shape = colorFactory.getRed();
shape.draw();
}
}
3.3 实现方式对比
实际场景中的业务非常多变,
- 当我们有新的产品是绿色的圆形时
实现方式一只需要添加一个新的GreenShapeFactory即可完成拓展,不需要改变原有的代码。
实现方式二需要在原有的工厂类上进行改动,添加一个新的 Shape getGreen(); 这样的方式显然不符合开闭原则
2. 当我们有新的产品是红色的三角形时
实现方式一需要在原有的工厂类上进行改动,添加一个新的 Shape getTriangle(); 这样的方式显然不符合开闭原则
实现方式一只需要添加一个新的TriangleColorFactory即可完成拓展,不需要改变原有的代码。
通过上述的对比我们可以得知,在采用工厂模式来进行设计时,我们需要清晰的了解到我们业务需要拓展的方向,选择合适的方式来进行搭建,这样才能写出更优秀的代码
4. 为什么不在类的构造函数中,封装创建的逻辑,反而非要采用工厂类来实现呢?
创建一个复杂对象的过程中,我们可能会需要做到很多初始化的工作,(可能会是一段很长的代码,甚至包含数据库的查询操作)如果我们将这些代码全部封装到构造函数中,会造成构造函数过于臃肿,而且也不符合 Java 面向对象的(封装,分派)原则。
Q: 面向对象的封装和分派原则讲的是什么?
尽量将很长的代码“分割”成多段,将每段再封装起来(减少段与段直接的耦合),这样就能将风险打散。以后需要修改时,只需要修改某段,不会在发生牵一发动全身的事情。