设计模式之工厂模式

创建型模式之工厂模式

什么是工厂模式

  • 工厂模式是java中最常见的创建型模式,客户端在不知道创建逻辑的情况下,只需要在工厂中直接创建即可

简单工厂模式

  • 简单工厂在创建对象的时候不需要知道具体的创建逻辑,客户端只需要知道该产品的一个标志即可,比如产品的名字
  • 必备的两个元素:
    • 产品的抽象类
    • 生产产品的工厂类

实现

  • 假设现在我们需要根据客户端的要求创建不同的图形,比如矩形,圆形…..,此时我们可以将图形抽象成接口,具体的产品只需要实现这个图形接口即可

简单工厂模式

  • shape接口(图形的接口,其中提供了一个创建图形的方法)
/*
 * 这个是抽象的产品类,后续的所有的产品都必须实现这个抽象类
 */
public interface Shape {
	public void draw();   //提供一个实现方法,作为画画的动作
}
  • 矩形产品类(实现shape接口)
/*
 * 矩形的产品类,其中实现了Shape这个类
 */
public class Rectangle implements Shape {

	/**
	 * 实现了Shape中的方法
	 */
	@Override
	public void draw() {
		System.out.println("我们画了一个矩形");

	}

}
  • 圆形产品类(实现Shape接口)
/*
 * 圆形的产品类,实现了Shape这个类
 */
public class Circle implements Shape {

	@Override
	public void draw() {
		System.out.println("我们画了一个圆");

	}
}
  • 工厂方法(创建产品的类)
    • 根据传入的标志创建对应的产品
/*
 * 简单工厂的实例
 * 其中提供一个getShape(String name) 可以根据提供的名字来返回一个对象,其实工厂生产的产品
 */
public class SimpleFactoryDemo {
	public Shape getShape(String name) {
		switch (name) {
		case "矩形":
			return new Rectangle(); // 返回矩形的对象
		case "圆形":
			return new Circle(); // 返回圆形对象
		default:
			System.out.println("我们不能创建一个额外的对象");
			return null; // 没有指定对象就返回null
		}

	}
}
  • 测试
public class ClientMain {
	public static void main(String[] args) {
		String name = "圆形"; // 填入名字
		SimpleFactoryDemo simpleFactoryDemo = new SimpleFactoryDemo(); // 创建简单工厂实例
		Shape shape = simpleFactoryDemo.getShape(name); // 根据名字获取对象
		shape.draw(); // 调用方法
	}
}

优缺点

  • 优点:
    • 每次增加一个产品类只需要增加一个实现类即可(实现产品接口)
  • 缺点:
    • 如果添加一个产品类,那么我们就需要在工厂类中添加对应的代码(违反开闭原则)
    • 开闭原则:
      • 简单的说就是在对功能进行扩展的时候对原先的代码不做任何修改

工厂方法模式

  • 简单工厂模式是一个抽象产品类派生出多个具体的产品类,但是一个工厂就生产了全部的产品
  • 工厂方法模式是有一个抽象工厂派生出多个具体的工厂,每个工厂生产一件具体的产品

条件

  1. 抽象产品类
  2. 抽象工厂类
  3. 每个具体的产品类都有一个具体的工厂类生产

实现

  • 我们对上面的实例进行改写,只需要定义一个抽象工厂类即可,其中派生出两个具体的工厂类用来生产圆形和矩形
  • 这里的抽象产品接口和具体的产品类和上面相同,不需要写了
  • 抽象工厂(使用的接口,其中有一个生产方法)
/*
 * 抽象的工厂类
 * 其中定义一个方法 getShape() 返回的是Shape类型的产品类
 */
public interface FactoryInterface {
	public Shape getShape();
}
  • 生产圆形的工厂类(实现抽象工厂)
/*
 * 生产圆形的产品类  其中实现了抽象的工厂类
 */
public class FactoryCircle implements FactoryInterface {

	@Override
	public Shape getShape() {
		return new Circle();
	}

}
  • 生产矩形的工厂类(实现抽象工厂接口)
/**
 * 生产矩形的工厂类,其中实现了抽象工厂类
 */
public class FactoryRectangle implements FactoryInterface {
	@Override
	public Shape getShape() {
		return new Rectangle();
	}
}
  • 测试类
public class ClientMain {
	public static void main(String[] args) {
		//使用多态创建工厂类
		FactoryInterface factoryInterface=new FactoryCircle();  //创建圆形的工厂类
		factoryInterface.getShape().draw();  //生成Circle对象并且调用方法

		FactoryInterface factoryInterface2=new FactoryRectangle();  //创建矩形的工厂类
		factoryInterface2.getShape().draw();   //生成Rectangle的对象并且调用方法


	}
}

优缺点

  • 优点:
    • 易于扩展,如果需要添加一个产品类,只需要添加一个具体的产品类和对应的工厂类即可,不需要对原工厂的方法进行任何的修改
    • 在工厂方法模式中,用户只需要知道所需要产品的具体工厂类即可,不需要知道具体的创建过程,甚至不需要知道具体产品类的类名。
  • 缺点:
    • 每次新增一个产品时,都需要增加一个具体的产品类和具体的工厂类,明显的成倍增加代码。

抽象工厂模式

  1. 多个抽象产品类,派生出多个具体产品类;一个抽象工厂类,派生出多个具体工厂类;每个具体工厂类可创建读个具体产品类实例。
  2. 即是提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们的具体的类。“一对多的关系”
  3. 这里的抽象产品类就像是一类产品的族,其中具体实现类就是不同的表现形式而已。
  4. 这里的每一个具体的工厂类可以生产不同种类的产品,并不是一个具体的工厂类只能生产一个具体的产品罢了
  5. 下面我们举一个麦当劳和肯德基的例子,他们两家中都买薯条和鸡翅,那么薯条和鸡翅就是两类产品,麦当劳和肯德基就是具体的工厂类用来生产薯条和鸡翅,那么我们需要一个抽象的工厂类来生产这两类产品,肯德基和麦当劳只需要实现即可。

总结定义

  • 简单的说:
    • 抽象工厂模式一个一个工厂生产一个产品类族
    • 其中的工厂并不是生产一种产品,而是生产多种产品(一类的产品)

条件

  • 多个抽象产品类派生出多个具体的产品类,比如鸡翅(麦当劳,肯德基),薯片(麦当劳,肯德基)
  • 一个抽象工厂,派生出多个具体的工厂类,比如肯德基和麦当劳就相当于两个工厂,这两个工厂都生产各自品牌的鸡翅,薯片,汉堡等

实现

  • 抽象产品类
    • 这里我们有两种产品,一个是鸡翅,一个薯片,因此需要创建两个抽象产品接口
    • 鸡翅的抽象接口
    • 薯片的抽象接口
    /*
    	* 薯条的接口,这也是一个抽象的产品类,其中可以有多个具体的产品类,比如麦当劳的薯条,肯德基的薯条
    	*/
    public interface IChips {
    	public void eat();
    }
/*
	* 鸡翅的接口,这是一类产品的接口,在其中可以实现具体的产品类,比如麦当劳的麦乐鸡,肯德基的奥尔良烤翅
*/
public interface IChicken {
public void eat();

}
  • 抽象工厂类
    • 抽象工厂类只有一个,但是具体的工厂类一个是麦当劳,一个肯德基,工厂中生产各自品牌的产品
    • 抽象工厂
/*
	* 抽象工厂类,用来生产鸡翅和薯条的工厂类,下面可以衍生出多个具体的工厂类来生产指定商家的鸡翅和薯条
	*/

public interface IStore {

	public IChicken createChicken(); // 生产鸡翅

	public IChips createChips(); // 生产薯条
}
  • 具体的产品类
    • 肯德基的薯条
    • 肯德基的鸡翅
    /*
    	* 肯德基的奥尔良烤翅类,是IChicken的具体实现类,是一个具体的产品
    	*/
    public class KfcChicken implements IChicken {
    
    	@Override
    	public void eat() {
    		System.out.println("你吃了肯德基的奥尔良烤翅......");
    
    	}
    }
    • 麦当劳的薯条
    /**
    	* 麦当劳的薯条,是IChips具体实现类,也是一个具体的产品类
    	*/
    public class McChips implements IChips {
    
    	@Override
    	public void eat() {
    		System.out.println("你吃了麦当劳的薯条......");
    
    	}
    }
    • 麦当劳的鸡翅
    /*
    	* 麦当劳的鸡翅,这是IChicken的具体的实现产品类
    	*/
    public class McChicken implements IChicken {
    
    		@Override
    		public void eat() {
    			System.out.println("你吃了的麦当劳的鸡翅......");
    
    		}
    	}
/**
 * 肯德基的薯条,是IChips具体实现类,也是一个具体的产品类
 */
public class KfcChips implements IChips {

	@Override
	public void eat() {
		System.out.println("你吃了肯德基的薯条......");

	}

 }
  • 具体的工厂类
    • 麦当劳的工厂类
    • 肯德基的工厂类
    /*
    	* 肯德基的工厂,实现了抽象工厂,这个工厂可以生产肯德基的鸡翅和薯条
    	*/
    public class KFCFactory implements IStore {
    
    	@Override
    	public IChicken createChicken() {
    		return new KfcChicken(); // 生产肯德基的鸡翅
    	}
    
    	@Override
    	public IChips createChips() {
    		return new KfcChips(); // 生产肯德基的薯条
    	}
    
    }
/*
	* 麦当劳的工厂,实现了抽象工厂,这个工厂可以生产麦当劳的鸡翅和薯条
	*/
public class McFactory implements IStore {

	@Override
	public IChicken createChicken() {
		return new McChicken(); // 生产麦当劳的鸡翅
	}

	@Override
	public IChips createChips() {
		return new McChips(); // 生产麦当劳的薯条
	}

}
  • 测试类
public class ClientMain {

	public static void main(String[] args) {

		IStore iStore1=new KFCFactory();   //创建肯德基的具体工厂类
		iStore1.createChicken().eat();    //吃了肯德基的鸡翅
		iStore1.createChips().eat();    //吃了肯德基的薯条

		IStore iStore2=new McFactory();   //创建麦当劳的具体工厂类
		iStore2.createChicken().eat();    //吃了麦当劳的鸡翅
		iStore2.createChips().eat();   //吃了麦当劳的薯条
	}

}

优缺点

  • 优点
    • 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
  • 缺点
    • 产品族比较难扩展,比如你要添加一个鞋子这个产品族,那么需要自己定义一个鞋子的抽象产品类,还要添加这个不同品牌的具体的产品实现类,另外还需要在抽象工厂里添加一个生产鞋子的方法

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿人谷

进制之间的转换

今天翻了一本计算机基础的书籍,其中十进制、二进制、八进制、十六进制之间的转换挺有意思的,也容易犯糊涂,特温故而知新。 十进制数制系统 十进制数制系统包括 1...

25610
来自专栏武培轩的专栏

设计模式-抽象工厂模式

在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方...

2815
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础-day01-代码题

Java基础day01-代码题巩固 ? ? 第一题:分析以下需求,并用代码实现 1.定义一个HelloWold类 2.在类中定义主方法 3.在主方法中使用输出语...

3476
来自专栏武培轩的专栏

设计模式-工厂方法模式

在简单工厂模式中,我们发现存在很多问题: 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。 要新增产品类的时候,就要修改工厂类的代码,...

3098
来自专栏C/C++基础

设计模式(6)——抽象工厂模式(Abstract Factory Pattern,创建型)

使用设计模式可以提高代码的可复用性、可扩充性和可维护性。抽象工厂模式(Abstract Factory Pattern)属于创建型模式,为创建一组相关或者相互依...

1001
来自专栏微信公众号:Java团长

Java回调机制(CallBack)详解

Java回调机制(CallBack),初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义。当然...

1252
来自专栏玄魂工作室

如何学python 第十七课 类-面向对象的概念

欢迎回来。今天要说的东西将会改变我们写程序的方式。今天我们介绍‘类’(class)。 概述 什么叫‘类’?类,类型。变量类型。从日常生活的感觉来说,‘类’其实...

2714
来自专栏aCloudDeveloper

漫谈递归转非递归

一:递归的思想       之前面试腾讯,面试官问了一个问题:说说递归和循环的区别?当时没有答出问题的本质,只是简单地解释了这两个词的意思,囧,今天就借由这篇文...

2957
来自专栏带你撸出一手好代码

lambda表达式杂谈

上面的数据存放着一组人员姓名、年龄、性别相关的信息。 现在有一个需求, 获得年龄20岁以上,性别为女的人的姓名。 看到需求后, 很多人脑袋中产生的解决方案可能是...

3344
来自专栏编程

三撩Python

我不求深刻,只求简单。 --三毛 1、起手 我呢,一个咖啡师,咖啡使我忙碌与充实。 每天端起咖啡,香气弥漫,轻轻一口,就在那一刹那,没有时间,没有空间,没有纷纷...

1819

扫码关注云+社区

领取腾讯云代金券