文章目录
工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
基本介绍
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决
主要解决接口选择的问题。
何时使用
我们明确地计划不同条件下创建不同实例时。
如何解决
让其子类实现工厂接口,返回的也是一个抽象的产品。
关键代码
创建过程在其子类执行。
应用实例
- 需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现;
- Hibernate 换数据库只需换方言和驱动就可以
优点
- 一个调用者想创建一个对象,只要知道其名称就可以了;
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
- 屏蔽产品的具体实现,调用者只关心产品的接口。
缺点
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
注意事项
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
项目需求
看一个披萨项目,需便于披萨种类的扩展,便于维护。
- 披萨的种类很多:(
GreeKPizz
、CheesePizz
等); - 披萨的制作有:
prepare
(准备材料)、bake
(制作)、cut
(切割)、box
(打包); - 完成披萨店订购功能。
分析
代码实现
public abstract class Pizza {
private String name;
public Pizza(String name){
this.name = name;
}
/**
* 由于不同类型的披萨需要的原材料不同,我们把准备原材料的方法制作为抽象方法
*/
public abstract void prepare();
/**
* 制作披萨
*/
public void bake(){
System.out.println("完成 " + name + " 的披萨制作");
}
/**
* 披萨切割
*/
public void cut(){
System.out.println("完成 " + name + " 的披萨切割");
}
/**
* 披萨切割
*/
public void box(){
System.out.println("完成 " + name + " 的披萨打包");
}
}
public class CheesePizza extends Pizza {
public CheesePizza() {
super("奶酪披萨");
}
@Override
public void prepare() {
System.out.println("完成 奶酪披萨 原材料准备");
}
}
public class GreekPizza extends Pizza{
public GreekPizza() {
super("希腊披萨");
}
@Override
public void prepare() {
System.out.println("完成希腊披萨原材料准备");
}
}
public class OrderPizza {
public OrderPizza(){
Pizza pizza = null;
String orderType;
orderType = getName();
if ("greek".equals(orderType)){
pizza = new GreekPizza();
}else if ("cheese".equals(orderType)){
pizza = new CheesePizza();
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
private String getName(){
String name = null;
try(BufferedReader inputStream = new BufferedReader(new InputStreamReader(System.in))){
System.out.println(" input pizza Type");
name = inputStream.readLine();
}catch (IOException exception){exception.printStackTrace();}
return name;
}
}
public class TestPizza {
public static void main(String[] args) {
new OrderPizza();
}
}
当出现一种新的披萨种类时就需要我们去修改代码,需要添加一种
Pizza
,然后去修改OrderPizza
类,当OrderPizza
有很多的时候修改的代码量就会有很多。分析:修改代码可以接受,但是如果我们在其他的地方也有创建
Pizza
的代码就意味着也需要修改,而创建Pizza
的代码往往有很多出。思路:把创建
Pizza
对象封装到一个类中,这样我们有新的Pizza
种类时只需要修改该类即可,其他创建到Pizza
对象的代码就不需要修改了 => 简单工程模式。
简单工厂模式
基本介绍
- 简单工厂模式是属于创建型模式,是工厂模式的一种,简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,简单工厂模式是工厂模式家族中最简单实用的模式;
- 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为;
- 在软件开发中,我们会用到大量的创建某中、某类或者某批对象时就会使用的工厂模式。
代码实现
public abstract class Pizza {
private String name;
public Pizza(String name){
this.name = name;
}
/**
* 由于不同类型的披萨需要的原材料不同,我们把准备原材料的方法制作为抽象方法
*/
public abstract void prepare();
/**
* 制作披萨
*/
public void bake(){
System.out.println("完成 " + name + " 的披萨制作");
}
/**
* 披萨切割
*/
public void cut(){
System.out.println("完成 " + name + " 的披萨切割");
}
/**
* 披萨切割
*/
public void box(){
System.out.println("完成 " + name + " 的披萨打包");
}
}
public class CheesePizza extends Pizza {
public CheesePizza() {
super("奶酪披萨");
}
@Override
public void prepare() {
System.out.println("完成 奶酪披萨 原材料准备");
}
}
public class GreekPizza extends Pizza{
public GreekPizza() {
super("希腊披萨");
}
@Override
public void prepare() {
System.out.println("完成希腊披萨原材料准备");
}
}
public class SimpleFactroy {
public Pizza createPizza(String orderType){
System.out.println("使用简单工厂模式");
Pizza pizza = null;
if ("greek".equals(orderType)){
pizza = new GreekPizza();
}else if ("cheese".equals(orderType)){
pizza = new CheesePizza();
}
return pizza;
}
//简单工厂模式也叫做静态工厂模式,一般选择一下形式
public static Pizza createPizza1(String orderType){
System.out.println("使用简单工厂模式1");
Pizza pizza = null;
if ("greek".equals(orderType)){
pizza = new GreekPizza();
}else if ("cheese".equals(orderType)){
pizza = new CheesePizza();
}
return pizza;
}
}
public class OrderPizza {
public OrderPizza(SimpleFactroy simpleFactroy){
setSimpleFactroy(simpleFactroy);
}
private SimpleFactroy simpleFactroy;
public void setSimpleFactroy(SimpleFactroy simpleFactroy) {
this.simpleFactroy = simpleFactroy;
Pizza pizza = simpleFactroy.createPizza(getName());
do{
if ( pizza != null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
break;
}
}while (true);
}
private String getName(){
String name = null;
try{
BufferedReader inputStream = new BufferedReader(new InputStreamReader(System.in));
System.out.println(" input pizza Type");
name = inputStream.readLine();
}catch (IOException exception){exception.printStackTrace();}
return name;
}
}
public class TestPizza {
public static void main(String[] args) {
new OrderPizza(new SimpleFactroy());
}
}
工厂方法模式
模拟需求
披萨项目:在客户在点披萨是,可以点不同口味的披萨,比如北京的奶酪披萨、北京的胡椒披萨、伦敦的奶酪披萨、伦敦的胡椒披萨;
分析
使用简单工厂模式,创建不同的简单工厂,比如北京披萨工厂、伦敦披萨工厂等,但是考虑到软件的可维护行、可扩展性并不是很好;
基本介绍
**工厂方法模式设计方案:**将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现;
**工厂方法模式:**定义一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式将对象的实例化推迟到子类。
代码实现
public class BJCheesePizza extends Pizza {
public BJCheesePizza() {
super("北京奶酪披萨");
}
@Override
public void prepare() {
System.out.println("完成 北京奶酪披萨 原材料准备");
}
}
public class BJGreekPizza extends Pizza {
public BJGreekPizza() {
super("北京希腊披萨");
}
@Override
public void prepare() {
System.out.println("完成北京希腊披萨原材料准备");
}
}
public class BjOrderPiazza extends OrderPiazza{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if ("greek".equals(orderType)){
pizza = new BJGreekPizza();
}else if ("cheese".equals(orderType)){
pizza = new BJCheesePizza();
}
return pizza;
}
}
public class LDCheesePizza extends Pizza {
public LDCheesePizza() {
super("伦敦奶酪披萨");
}
@Override
public void prepare() {
System.out.println("完成 伦敦奶酪披萨 原材料准备");
}
}
public class LDGreekPizza extends Pizza {
public LDGreekPizza() {
super("伦敦希腊披萨");
}
@Override
public void prepare() {
System.out.println("完成 伦敦希腊披 萨原材料准备");
}
}
public class LDOrderPiazza extends OrderPiazza{
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if ("greek".equals(orderType)){
pizza = new BJGreekPizza();
}else if ("cheese".equals(orderType)){
pizza = new BJCheesePizza();
}
return pizza;
}
}
public abstract class OrderPiazza {
public abstract Pizza createPizza(String orderType);
public void getPizza(){
do{
Pizza pizza = createPizza(getName());
if ( pizza != null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
break;
}
}while (true);
}
private String getName(){
String name = null;
try{
BufferedReader inputStream = new BufferedReader(new InputStreamReader(System.in));
System.out.println(" input pizza Type");
name = inputStream.readLine();
}catch (IOException exception){exception.printStackTrace();}
return name;
}
}
public abstract class Pizza {
private String name;
public Pizza(String name){
this.name = name;
}
/**
* 由于不同类型的披萨需要的原材料不同,我们把准备原材料的方法制作为抽象方法
*/
public abstract void prepare();
/**
* 制作披萨
*/
public void bake(){
System.out.println("完成 " + name + " 的披萨制作");
}
/**
* 披萨切割
*/
public void cut(){
System.out.println("完成 " + name + " 的披萨切割");
}
/**
* 披萨切割
*/
public void box(){
System.out.println("完成 " + name + " 的披萨打包");
}
}
public class TestPizza {
public static void main(String[] args) {
OrderPiazza piazza = new LDOrderPiazza();
piazza.getPizza();
}
}
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
基本介绍
- 抽象工厂模式:定义了一个
接口
用于创建相关或有依赖关系的对象簇,而无需指明具体的类; - 抽象工程模式可以看出将简单工厂模式和工厂方法模式进行整合;
- 在设计层面看,抽象工厂模式就是对简单工厂模式的改进或者称为
进一步的抽象
; - 将工厂抽象成两层,
ABSFactory
抽象工厂和具体实现的工厂子类。我们可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
主要解决
主要解决接口选择的问题。
何时使用
系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
如何解决
在一个产品族里面,定义多个产品。
关键代码
在一个工厂里聚合多个同类产品。
应用实例
工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。
优点
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点
产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
代码实现
public interface ABSFactory {
Pizza createPizza(String orderType);
}
public class BJCheesePizza extends Pizza {
public BJCheesePizza() {
super("北京奶酪披萨");
}
@Override
public void prepare() {
System.out.println("完成 北京奶酪披萨 原材料准备");
}
}
public class BJFactory implements ABSFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if ("greek".equals(orderType)){
pizza = new BJGreekPizza();
}else if ("cheese".equals(orderType)){
pizza = new BJCheesePizza();
}
return pizza;
}
}
public class BJGreekPizza extends Pizza {
public BJGreekPizza() {
super("北京希腊披萨");
}
@Override
public void prepare() {
System.out.println("完成北京希腊披萨原材料准备");
}
}
public class LDCheesePizza extends Pizza {
public LDCheesePizza() {
super("伦敦奶酪披萨");
}
@Override
public void prepare() {
System.out.println("完成 伦敦奶酪披萨 原材料准备");
}
}
public class LDFcatory implements ABSFactory {
@Override
public Pizza createPizza(String orderType) {
Pizza pizza = null;
if ("greek".equals(orderType)){
pizza = new LDGreekPizza();
}else if ("cheese".equals(orderType)){
pizza = new LDCheesePizza();
}
return pizza;
}
}
public class LDGreekPizza extends Pizza {
public LDGreekPizza() {
super("伦敦希腊披萨");
}
@Override
public void prepare() {
System.out.println("完成 伦敦希腊披 萨原材料准备");
}
}
public class OrderPiazza {
private ABSFactory factory;
private void setFactory(ABSFactory factory) {
this.factory = factory;
}
public OrderPiazza(ABSFactory factory){
setFactory(factory);
}
public void getPizza(){
do{
Pizza pizza = factory.createPizza(getName());
if ( pizza != null){
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}else{
break;
}
}while (true);
}
private String getName(){
String name = null;
try{
BufferedReader inputStream = new BufferedReader(new InputStreamReader(System.in));
System.out.println(" input pizza Type");
name = inputStream.readLine();
}catch (IOException exception){exception.printStackTrace();}
return name;
}
}
public abstract class Pizza {
private String name;
public Pizza(String name){
this.name = name;
}
/**
* 由于不同类型的披萨需要的原材料不同,我们把准备原材料的方法制作为抽象方法
*/
public abstract void prepare();
/**
* 制作披萨
*/
public void bake(){
System.out.println("完成 " + name + " 的披萨制作");
}
/**
* 披萨切割
*/
public void cut(){
System.out.println("完成 " + name + " 的披萨切割");
}
/**
* 披萨切割
*/
public void box(){
System.out.println("完成 " + name + " 的披萨打包");
}
}
public class TestPizza {
public static void main(String[] args) {
new OrderPiazza(new BJFactory()).getPizza();
}
}
源码分析
JDK
JDL中的Calendar
类中就使用了简单工厂模式;
根据不同的类型会创建不同的对象;
小结
- 工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系进行解耦,从而提高项目的可扩展性和维护性;
- 三种工厂模式(
简单工厂模式
、工厂方法模式
、抽象工厂模式
); - 创建对象实例时,不要直接
new 类
,而是吧这个new 类
的动作放到一个工厂的方法中并返回,变量不要直接持有具体类的引用; - 不要让类集成具体类,而是集成抽象类或者实现接口;
- 披萨切割
*/
public void box(){
System.out.println(“完成 " + name + " 的披萨打包”);
}
}
public class TestPizza {
public static void main(String[] args) {
new OrderPiazza(new BJFactory()).getPizza();
}
}
# 源码分析
## JDK
JDL中的`Calendar`类中就使用了简单工厂模式;
[外链图片转存中...(img-e3bhzbVU-1712566022861)]
根据不同的类型会创建不同的对象;
[外链图片转存中...(img-eOKFjAt6-1712566022861)]
[外链图片转存中...(img-v4hp4WKY-1712566022861)]
[外链图片转存中...(img-T7IJVwVU-1712566022861)]
## 小结
- 工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系进行解耦,从而提高项目的可扩展性和维护性;
- 三种工厂模式(`简单工厂模式`、`工厂方法模式`、`抽象工厂模式`);
- 创建对象实例时,不要直接`new 类`,而是吧这个`new 类`的动作放到一个工厂的方法中并返回,**变量不要直接持有具体类的引用**;
- 不要让类集成具体类,而是集成抽象类或者实现接口;
- 不要覆盖基类中已经实现的方法。