Java设计模式之简单工厂 工厂方法 抽象工厂深度总结

目录
  • 工厂模式介绍
    • 好处
    • 常见的应用
  • 简单工厂(Simple Factory)
    • 适用场景
    • 角色分配:
    • 应用案例:
    • 优缺点:
    • 简单工厂实现:
  • 工厂方法(Factory Method)
    • 适用场景
    • 角色分配:
    • 应用案例:
    • 优缺点:
    • 工厂方法实现:
  • 抽象工厂(Abstract Factory)
    • 适用场景
    • 角色分配
    • 应用案例:
    • 优缺点:
    • 抽象工厂实现
    • 抽象工厂终极改进(反射+配置文件+简单工厂)

工厂模式介绍

工厂模式也是非常常见的设计模式之一,其属于创建型模式。工厂模式分类:简单工厂(Simple Factory)、工厂方法(Factory Method)、抽象工厂(Abstract Factory),严格来讲,简单工厂不属于工厂设计模式。

好处

  • 解耦:工厂模式主要是为了对象的创建和使用的分离
  • 降低代码重复:如果对象创建很复杂,则每次创建都需要重复很多代码,通过工厂包装起来可以减少重复代码
  • 方便维护:如果创建对象的逻辑有修改,则只需要修改工厂内代码,而不用修改每个创建对象的代码。

常见的应用

  • Spring中的BeanFactory.getBean(beanName)
  • 日志当中的LoggerFactory.getLogger(name)
  • Java加密时 KeyGenerator keygen=KeyGenerator.getInstance("AES");
  • RabbitMQ的Java客户端创建连接 :
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory("192.168.74.4");
// 通过连接工厂获取连接
Connection connection = factory.newConnection();

简单工厂(Simple Factory)

简单工厂并不在23种设计模式之中,属于特殊的工厂模式,应用的相对来说少一点。客户端实例化对象的时候不用通过new Audi()的方式,而是可以通过往统一工厂传入相应的条件返回对应的实例对象(主要通过if-else或者switch-case进行判断,违背了开闭原则),屏蔽了实例化对象的具体逻辑细节。

适用场景

  1. 需要创建的对象较少。
  2. 客户端不关心对象的创建过程。

角色分配:

  • 工厂(Factory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
  • 抽象产品(Product)角色 :简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
  • 具体产品(Concrete Product)角色:简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。

其UML类图如下所示:

应用案例:

  • Java加密时 KeyGenerator keygen=KeyGenerator.getInstance("AES");
  • DateFormat类中的public final static DateFormat getDateInstance(int style)

优缺点:

  • 优点:实现简单,隐藏了创建对象的细节,创建对象的逻辑修改时,客户端不用进行修改。
  • 缺点:违背了开闭原则,每次新增删除子类的时候都要修改工厂的逻辑,而且创建对象的逻辑都包含在工厂内,后面子类太多的话这块代码会非常多,难以维护。

简单工厂实现:

我们创建一个Car接口,里面包含一个getName方法用以返回具体的品牌名称,接口有两个实现类Audi和Bmw,分别返回了品牌名称 "Audi" 和 "Bmw"。

package com.wkp.designpattern.factory;
//汽车接口
public interface Car {

	//返回汽车的品牌
	public String getName();
}
package com.wkp.designpattern.factory;

public class Audi implements Car {

	public String getName() {
		return "Audi";
	}
}
package com.wkp.designpattern.factory;

public class Bmw implements Car {

	public String getName() {
		return "Bmw";
	}
}

下面是简单工厂的核心,用于创建对象

package com.wkp.designpattern.simple.factory;

import com.wkp.designpattern.factory.Audi;
import com.wkp.designpattern.factory.Bmw;
import com.wkp.designpattern.factory.Car;

public class SimpleFactory {

	public Car getCar(String name){
		if("Audi".equals(name)){
			return new Audi();
		}else if("Bmw".equals(name)){
			return new Bmw();
		}else{
			System.out.println("没法生产这个车");
			return null;
		}
	}
}

测试代码如下:

package com.wkp.designpattern.simple.factory;
import com.wkp.designpattern.factory.Car;

public class SimpleFactoryTest {

	public static void main(String[] args) {
		SimpleFactory factory = new SimpleFactory();

		Car car1 = factory.getCar("Audi");
		System.out.println(car1.getName());
		Car car2 = factory.getCar("Bmw");
		System.out.println(car2.getName());
	}
}

输出结果如下:

Audi
Bmw

这里每增加一个新的子类,getCar方法就要添加if判断,删除了子类这里也要修改,显然违反了开闭原则,而且创建对象的逻辑全部都在这个方法中,随着创建对象的增加,这里的逻辑会非常多。当然我们可以通过反射的方式对上面的工厂进行改进如下:

//利用反射改进的简单工厂,添加的时候不用修改getCar方法
public class ReflectSimpleFactory {

	//参数className为完整类名
	public Car getCar(String className){
		Car obj=null;
		try {
			obj=(Car) Class.forName(className).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return obj;
	}
}
public class ReflectSimpleFactoryTest {

	public static void main(String[] args) {
		ReflectSimpleFactory factory = new ReflectSimpleFactory();
		Car car1 = factory.getCar("com.wkp.designpattern.factory.Audi");
		System.out.println(car1.getName());
		Car car2 = factory.getCar("com.wkp.designpattern.factory.Bmw");
		System.out.println(car2.getName());
	}
}

输出结果不变,也符合了开闭原则,但是要传入完整类名也不方便,可以通过xml或者配置文件的方式进行改进。

工厂方法(Factory Method)

工厂方法的应用是最多的,工厂方法中不再提供统一的工厂创建对象,而是针对不同的对象提供不同的工厂。定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,创建过程延迟到子类进行。

适用场景

  • 当一个类不知道它所必须创建的对象的类的时候:工厂方法模式中客户端不需要知道对象的名称,只需要知道要创建的对象对应的工厂即可。
  • 当一个类希望由它的子类来指定它所创建的对象的时候:工厂方法模式中定义了一个Factory接口,该接口包含一个创建对象的抽象方法,具体的创建对象的逻辑由其实现类完成。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

角色分配:

  • 抽象工厂(Abstract Factory)角色:是工厂方法模式的核心,提供了创建对象的接口,任何在模式中创建的对象的工厂类必须实现这个接口。
  • 具体工厂(Concrete Factory)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
  • 抽象产品(AbstractProduct)角色 :工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
  • 具体产品(Concrete Product)角色 :这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应

其UML类图如下所示:

应用案例:

  • spring-data-redis中创建redis连接的地方,RedisConnectionFactory接口提供了创建连接的方法RedisConnection getConnection(),该工厂的两个实现类JedisConnectionFactory ,LettuceConnectionFactory分别用于创建jedis和lettuce连接

优缺点:

  • 优点:符合开闭原则,添加子类时只需要添加对应的工厂类即可,而不用修改原有的工厂类,每个对象的创建逻辑都在对应的工厂类中,代码逻辑清晰,易于维护。
  • 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

工厂方法实现:

定义一个Factory接口,里面提供了一个getCar()方法,具体的创建逻辑由其实现类去完成。

public interface Factory {

	public Car getCar();
}

下面是Factory接口的具体实现类,用于创建对应的对象

public class AudiFactory implements Factory {

	public Car getCar() {
		return new Audi();
	}
}
public class BmwFactory implements Factory {

	public Car getCar() {
		return new Bmw();
	}
}

测试类如下:

public class FuncFactoryTest {

	public static void main(String[] args) {
		Car car1 = new AudiFactory().getCar();
		System.out.println(car1.getName());

		Car car2 = new BmwFactory().getCar();
		System.out.println(car2.getName());
	}
}

抽象工厂(Abstract Factory)

上面的工厂模式生产的都是一类产品,而抽象工厂模式可以生产产品族。什么是产品族呢?其实就是一组具有关联关系的产品集合,举几个例子:

  • 比如生产电脑,用Intel系列、AMD系列的零件(CPU、主板。。。。。),每个系列的零件就是一个产品族。
  • 比如我们开发过程中会用到MySQL、Oracle数据库,而不同的数据库的操作会有不同,比如有User,Order两个类,两个类都有添加、修改操作,那User、Order的操作就要随着数据库的切换而切换,MySQL和Oracle下不同的类就组成了两个产品族。
  • 我们用QQ空间的时候会有换皮肤的功能,而每套皮肤下的背景、按钮、导航、菜单。。。。。。这些也构成了产品族
  • 我们上面用的生产汽车的例子,比如奥迪,宝马不同品牌车的零部件(轮胎、发动机、轴承。。。。。。)

适用场景

  • 和工厂方法一样客户端不需要知道它所创建的对象的类。
  • 需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况。(同属于同一个产品族的产品)
  • 系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)

角色分配

  • 抽象工厂(AbstractFactory)角色 :是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
  • 具体工厂类(ConcreteFactory)角色 :这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建某一种产品对象。
  • 抽象产品(Abstract Product)角色 :工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
  • 具体产品(Concrete Product)角色 :抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。在抽象工厂中创建的产品属于同一产品族,这不同于工厂模式中的工厂只创建单一产品。

其UML类图如下所示:

应用案例:

QQ空间换肤、更换数据库等

优缺点:

  • 优点:可以创建系列产品,方便切换使用的产品系列。
  • 缺点:扩展产品族较为麻烦,不光要添加所有的抽象产品实现,还要添加产品族对应的工厂;另外添加产品也不简单,要添加抽象产品,所有的产品族实现,还要对原先的工厂实现添加工厂方法以生产新产品。

抽象工厂实现

这个案例我们就以生产电脑为例,众所周知目前电脑的CPU有两大品牌:Intel和AMD。我们就以此为例,如果电脑选用Intel系列,就要用Intel的CPU和主板等,如果用AMD系列,就用AMD系列的零部件。

下面的两个接口就是我们上面提到的抽象产品角色。

//CPU
public interface CPU {

	public String getName();
}
//主板
public interface MainBoard {

	public String getName();
}

下面的四个类就是我们上面提到的具体产品角色。首先是Intel系列产品

public class IntelCPU implements CPU {

	public String getName() {
		return "IntelCPU";
	}

}
public class IntelMainBoard implements MainBoard{

	public String getName() {
		return "IntelMainBoard";
	}

}

然后是AMD系列产品:

public class AMDCPU implements CPU {

	public String getName() {
		return "AMDCPU";
	}

}
public class AMDMainBoard implements MainBoard{

	public String getName() {
		return "AMDMainBoard";
	}

}

下面的Factory就是抽象工厂角色,提供了生产CPU和主板的抽象方法。

public interface Factory {
	//生产CPU
	public CPU createCPU();
	//生产主板
	public MainBoard createMainBoard();
}

然后是具体的工厂类角色,分别生产不同系列的产品。

//Intel系列产品工厂
public class IntelFactory implements Factory {

	public CPU createCPU() {
		return new IntelCPU();
	}

	public MainBoard createMainBoard() {
		return new IntelMainBoard();
	}

}
//AMD系列产品工厂
public class AMDFactory implements Factory {

	public CPU createCPU() {
		return new AMDCPU();
	}

	public MainBoard createMainBoard() {
		return new AMDMainBoard();
	}

}

测试类如下:

public class FactoryTest {

	public static void main(String[] args) {
		Factory intel = new IntelFactory();
		System.out.println(intel.createCPU().getName());
		System.out.println(intel.createMainBoard().getName());

		Factory amd = new AMDFactory();
		System.out.println(amd.createCPU().getName());
		System.out.println(amd.createMainBoard().getName());
	}
}

运行结果为:

IntelCPU
IntelMainBoard
AMDCPU
AMDMainBoard

抽象工厂终极改进(反射+配置文件+简单工厂)

上面也说过抽象工厂的缺点是扩展产品族比较麻烦,我们对上面的抽象工厂做个改进,使其在添加产品族的时候更简单一些。我们引入简单工厂,但是简单工厂扩展的时候要添加判断条件,所以我们可以通过反射+配置文件去解决这个问题。改动后的UML图如下所示:

改进后的代码如下所示:Configuration类用于读取配置文件(没有具体去实现)

type=Intel
packageName=com.wkp.design.pattern.factory.abst
public class SimpleFactory {

	static class Configuration{
		public static String get(String key){
			String value="";//TODO 读取配置文件得到value
			return value;
		}
	}

	//通过配置文件读取产品族类型及包名
	private static final String type=Configuration.get("type");
	private static final String packageName=Configuration.get("packageName");

	//生产CPU
	public CPU createCPU() throws Exception{
		return (CPU)Class.forName(packageName+"."+type+"CPU").newInstance();
	}
	//生产主板
	public MainBoard createMainBoard() throws Exception{
		return (MainBoard)Class.forName(packageName+"."+type+"MainBoard").newInstance();
	}
}

测试代码如下

public class SimpleFactoryTest {

	public static void main(String[] args) throws Exception {
		SimpleFactory factory = new SimpleFactory();
		System.out.println(factory.createCPU().getName());
		System.out.println(factory.createMainBoard().getName());
	}
}

我们看到,在调用的时候客户端完全不用管用的是Intel还是AMD,这样如果想切换产品族的话,只需要修改配置文件即可,非常的方便。

到此这篇关于Java设计模式之简单工厂 工厂方法 抽象工厂深度总结的文章就介绍到这了,更多相关Java 设计模式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java以命令模式设计模式

    目录 Java以命令模式设计模式 1.简单介绍 2.命令模式 Java以命令模式设计模式 1.简单介绍 意图: 将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化. 主要解决: 在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录.撤销或重做.事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适. 何时使用: 在某些场合,比如要对行为进行"记录.撤销/重做.事务"等处理,这种无法抵御变化的紧耦合是不合适的.在这种情况下,如何将

  • Java设计模式--适配器模式详解

    目录 定义 结构 示例 扩展 总结 定义 适配器模式用于解决接口间的兼容问题. 当我们需要使用某个类提供的接口,但是这个接口与现在的系统需求不符,由于该接口是由第三方提供的,或者是已经在生产上跑了很久的存量类,我们不想通过改变这个类来满足现在系统的需求,那么这时候就可以考虑通过将目标类封装成一个满足系统需求的新类,因此适配器(Adapter)也称为包装器(Wrapper). 结构 适配器模式包含如下角色: Target:目标抽象类,客户类期望的接口. Adapter:适配器类,适配器模式的核心,

  • JAVA设计模式---单例模式你知道吗

    目录 单例模式的介绍 单例模式实现的八种方式 饿汉式 静态常量 静态代码块 懒汉式 线程不安全的写法 线程安全,同步锁-效率低,不推荐 线程安全,同步代码块-无法解决线程安全问题,不推荐 双重检查-解决线程安全和懒加载问题–推荐使用 静态内部类-可以实现懒加载,线程安全,推荐使用 枚举 单例模式注意事项 总结 单例模式的介绍 单例模式实现的八种方式 饿汉式 静态常量 步骤: 1.构造器私有化(防止new) 2.类的内部创建对象 3.向外暴露一个静态的公共方法-getInstance //饿汉式静

  • JAVA设计模式---原型模式你了解吗

    目录 介绍 角色 Java语言提供的clone()方法 代码演示-克隆羊 结论 深浅拷贝 深浅拷贝探讨 实现深克隆的方式一 : 手动对引用对象进行克隆 实现深克隆的方式二 :序列化 原型模式对单例模式的破坏 优缺点 原型模式在Spring中的应用场景 总结 介绍 原型模式(Prototype Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.原型模式是一种对象创建型模式. 原型模式的工作原理很简单:将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过

  • Java设计模式之简单工厂 工厂方法 抽象工厂深度总结

    目录 工厂模式介绍 好处 常见的应用 简单工厂(Simple Factory) 适用场景 角色分配: 应用案例: 优缺点: 简单工厂实现: 工厂方法(Factory Method) 适用场景 角色分配: 应用案例: 优缺点: 工厂方法实现: 抽象工厂(Abstract Factory) 适用场景 角色分配 应用案例: 优缺点: 抽象工厂实现 抽象工厂终极改进(反射+配置文件+简单工厂) 工厂模式介绍 工厂模式也是非常常见的设计模式之一,其属于创建型模式.工厂模式分类:简单工厂(Simple Fa

  • JavaScript设计模式之工厂模式和抽象工厂模式定义与用法分析

    本文实例讲述了JavaScript设计模式之工厂模式和抽象工厂模式定义与用法.分享给大家供大家参考,具体如下: 1.工厂模式: 虽然Object构造函数和对象字面量都可以用来创建单个对象,但这个方式有个明显的缺点:使用同一个接口创建很多对象,会产生大量重复的代码.为了解决这个问题,开始使用工厂模式. 利用工厂模式,可以实现不指定特定的类而创建出对象,也就是说,不需要使用new关键字来创建特定类或子类的实例. var TravelTeam = function(){}; TravelTeam.pr

  • 轻松掌握Java工厂模式、抽象工厂模式

    在面向对象编程的程序设计中,我们最常见的操作就是new对象,但在创建一个新对象的过程中,会有一些问题,比如我们需要注意创建新对象的实现细节,初始化一些必要的参数等.这样会让我们在讲更多的心思放在对象的创建上,而不是程序逻辑的实现上,严重拖延了我们的程序开发效率.工厂模式和抽象工厂模式的出现则完美解决了这个问题,让我们不再关心对象的创建,更多的在重心放在业务的实现上. 特点: 1.程序员直接通过工厂方法创建对象,不再关注创建对象的细节. 2.隐藏对象的实现细节,也有利于程序的安全性. 3.降低程序

  • Java工厂模式之简单工厂,工厂方法,抽象工厂模式详解

    目录 1.简单工厂模式 1.定义 2.代码案例 3.适用场景 4.优缺点 2.工厂方法模式 1.定义 2.代码案例 3.适用场景 4.优缺点 3.抽象工厂模式 1.定义 2.代码案例 3.适用场景 4.优缺点 4.总结 1.简单工厂模式 1.定义 简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例.属于创建型模式,但它不属于GOF23种设计模式. 2.代码案例 假设以罐头产品的制造为案例 第一步:定义罐头的顶层接口类ICanned /**

  • 深入理解Java设计模式之简单工厂模式

    目录 一.什么是简单工厂模式 二.简单工厂模式的结构 三.简单工厂模式的应用场景 四.简单工厂模式和工厂方法模式区别 五.简单工厂模式和策略模式的异同 六.简单工厂模式的优缺点 七.简单工厂模式的实现 八.总结 一.什么是简单工厂模式 简单工厂模式又称为静态工厂模式,实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例.简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例. 其实就是将一个具体类的实例化交给一个静态工厂方法来执

  • 举例讲解Python设计模式编程的代理模式与抽象工厂模式

    代理模式 Proxy模式是一种常用的设计模式,它主要用来通过一个对象(比如B)给一个对象(比如A) 提供'代理'的方式方式访问.比如一个对象不方便直接引用,代理就在这个对象和访问者之间做了中介 你先设想:一个对象提供rgb三种颜色值,我想获得一个对象的rgb三种颜色,但是我不想让你获得蓝色属性,怎么办? class Proxy(object): def __init__(self, subject): self.__subject = subject # 代理其实本质上就是属性的委托 def _

  • java使用dom4j解析xml配置文件实现抽象工厂反射示例

    逻辑描述: 现在我们想在B层和D层加上接口层,并使用工厂.而我们可以将创建B和创建D看作是两个系列,然后就可以使用抽象工厂进行创建了. 配置文件:beans-config.xml.service-class与dao-class分别对应两个系列的产品.子菜单中id对应接口的命名空间,class对应实现类的命名空间. 复制代码 代码如下: [html] view plaincopyprint? <?xml version="1.0" encoding="UTF-8"

  • java设计模式之简单工厂模式简述

    简单工厂模式的概念 就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建.简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例. 简单工厂模式的UML图 简单工厂模式代码 学习简单工厂模式的时候我用的是一个与人类有相关的例子.人类在世界分为男人和女人,首先定义一个Human产品的抽象接口 /** * This is factory patter package */ package com.roc.factory; /** *

  • java设计模式之简单工厂模式详解

    简单工厂模式:由一个工厂对象决定创建出哪一种类的实例. 1.抽象类 public abstract class People { public abstract void doSth(); } 2.具体类 public class Man extends People{ @Override public void doSth() { System.out.println("I'm a man,I'm coding."); } } 3.具体类 public class Girl exte

  • java设计模式之简单工厂模式

    在编写一个计算器程序时,可以将业务逻辑和显示分离,业务逻辑封装为一个类(封装):如果要新添加一种运算,可以先创建一个Operation的基类,然后各种运算从Operation类继承,并实现GetResult()虚函数,这时添加新的运算只需要派生一个新的类,即不需要之前的运算参与编译.如何让计算器知道我是希望使用哪种运算呢?应该考虑单独的类来做这个创造实例的过程,这就是工厂.创建一个OperationFactory类,传入参数,函数createOperate就可以实例化出合适的对象. Java代码

随机推荐