java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java 设计模式

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

作者:没头脑遇到不高兴

设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案

工厂模式介绍

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

好处

常见的应用

//创建连接工厂
ConnectionFactory factory = new ConnectionFactory("192.168.74.4");
// 通过连接工厂获取连接
Connection connection = factory.newConnection();

简单工厂(Simple Factory)

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

适用场景

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

角色分配:

其UML类图如下所示:

应用案例:

优缺点:

简单工厂实现:

我们创建一个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)

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

适用场景

角色分配:

其UML类图如下所示:

应用案例:

优缺点:

工厂方法实现:

定义一个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)

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

适用场景

角色分配

其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 设计模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文