设计模式-三种工厂模式简介

设计模式-工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

工厂模式主要是为创建对象提供了接口。工厂模式按照《Java与模式》中的提法分为三类:

  1. 简单工厂模式(Simple Factory)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)

简单工厂模式不是我们常说的23种设计模式中的一种,那个23种设计模式中的工厂模式只包含工厂方法和抽象工厂。

下面我们就介绍一下,这三种模式。

简单工厂

简单工厂模式又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

概念:说的通俗些就是工厂根据不同的参数创建对应的产品。

简单工厂

 /**
 * 抽象产品  Car
 * @author hobart
 */
public abstract class Car {
	private String name;  
	public abstract void drive();
	public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
}
/**
 * 具体产品  Bmw
 * @author hobart
 */
public class Bmw extends Car {
	public void drive() {
		System.out.println(this.getName()+"车----已启动-----------------");  
	}
}
/**
 * 具体产品  Benz
 * @author hobart
 */
public class Benz extends Car {
	public void drive() {
		System.out.println(this.getName()+"车----已启动-----------------");  
	}
}
/**
 * 不存在的产品  Bhq
 * @author hobart
 */
public class Bhq extends Car {
	public void drive() {
		System.out.println(this.getName()+"车----不存在-----------------"); 		
	}
} 
/**
 * 简单工厂
 * @author hobart
 */
public class DriverSimpleFactory {
	public static Car createCar(String car){  
        Car c = null;  
        if("Benz".equalsIgnoreCase(car)) {
        	c = new Benz();  
        } else if("BMW".equalsIgnoreCase(car)) {  
            c = new Bmw();  
        } else {
        	c = new Bhq();
        }
        return c;  
    }  
}
/**
 * 测试
 * @author hobart
 */
public class DriveTest {
	public static void main(String[] args) {  
        Car car = DriverSimpleFactory.createCar("benz");  
        car.setName("bmw");  
         //司机开着bmw出发  
        car.drive();  
    }  
}

UML图

简单工厂

优点: 简单工厂包含逻辑判断,根据客户端实例化相关类,去除与具体产品依赖,客户端不管哪个类的实例,把需求给工厂,工厂单独创建相应实例。是优点也是不足。它方便扩展算法,比如增加一个开根号的功能,我们只要继续继承运算类就行了,同时客户端也就是使用者不知道具体的实现细节,只要给出相关标示符,工厂函数就马上给他创建一个他想要的实体就行了。减少了使用者和功能开发者之间的耦合度。

缺点: 比较明显,在进行扩展的时候,需要修改工厂类的那个分支语句Switch,这样便违背OCP原则[开闭原则(Open Closed Principle)],而且当有多级结构继承的时候,简单工厂就会因为只能对应平行一层记得继承,不得不使得好多类继承同一个接口,然后得到A*B这么多的工厂实体可能,工厂函数很难维护。

工厂方法

定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使得一个类的实例化延迟到了子类。

概念:工厂方法有别于简单工厂却是简单工厂的升级。

不同之处:

简单工厂是通过参数来控制产品的生产、这里使用的是重载。不同的工厂实现同一个工厂方法生产不同的产品。

工厂方法是一个工厂生产一个产品(一对一)。如需增加产品、首先要增加工厂。是一对一的生产对象的模式,更符合OCP原则(开闭原则)。

工厂方法

/**
 * 抽象产品  Car
 * @author hobart
 */
public abstract class Car{  
	private String name;
	public abstract  void drive();	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}	
}
/**
 * 具体产品  Bmw
 * @author hobart
 */
public class Bmw extends Car {
	public void drive() {
		System.out.println(this.getName()+"车----已启动-----------------");  
	}
}
/**
 * 具体产品  Benz
 * @author hobart
 */
public class Benz extends Car {
	public void drive() {
		System.out.println(this.getName()+"车----已启动-----------------");  
	}
}
/**
 * 不存在的产品  Bhq
 * @author hobart
 */
public class Bhq extends Car {
	public void drive() {
		System.out.println(this.getName()+"车----是无法生产的车---------"); 
	}
}
/**
 * 抽象工厂
 * @author hobart
 */
public abstract class DriverFactoryMethod {
	public abstract Car createCar(String car);  
}
/**
 * 具体工厂 BenzDriver(每个具体工厂负责一个具体产品) 
 * @author hobart
 */
public class BenzDriverFactoryMethod extends DriverFactoryMethod {
	@Override
	public Car createCar(String car) {
		if("Benz".equalsIgnoreCase(car)) {
			return new Benz(); 
		} else {
			return new Bhq(); 
		}
	}
}
/**
 * 具体工厂 BmwDriver(每个具体工厂负责一个具体产品) 
 * @author hobart
 */
public class BmwDriverFactoryMethod extends DriverFactoryMethod {
	@Override
	public Car createCar(String car) {
		if("BMW".equalsIgnoreCase(car)) {
			return new Bmw(); 
		} else {
			return new Bhq(); 
		}
	}
}
/**
 * 测试
 * @author hobart
 */
public class DriveTest {
	public static void main(String[] args) {  
		DriverFactoryMethod d = new BenzDriverFactoryMethod(); 
        Car car = d.createCar("benz");  
        car.setName("benz");  
         //司机开着benz出发  
        car.drive();  
    }  
}

UML图

工厂方法

优点: 遵守开闭原则,直接添加具体产品类和相应工厂类,实例化哪一个工厂放在客户端, 算法实体的创建被延迟到了工厂子类里,我们不在工厂里直接创建对象,而是直接封装一个一个的小工厂,每个工厂负责创建自己的子类,这样就不存在switch的情况,也就不存在扩展不满足OCP的这个问题。

缺点:

第一:增加一个产品就要增加一个产品工厂类,额外开发.

第二:把简单工厂内部逻辑移到客户端,所以之前修改工厂类,现在修改客户端,问题还是存在.

如果算法种类很多,那么继承抽象工厂的子类也就会很多,不是很好维护,同时不支持产品切换,比如我们要开发PC,分为多个系统,那么我们可以把所有的系统都抽象出来,然后我们在抽象出来工厂,但是如果这个时候我们有两个硬件呢,PC和Phone,虽然我们可以保证只有这两个硬件了,但是如果用基本的抽象工厂去实现的话还是很别扭。

抽象工厂

抽象工厂模式(Abstract Factory Pattern)提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类,它是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

概念:说的明白些抽象工厂就是 简单工厂+工厂方法。

抽象工厂

/**
 * 抽象产品  Car
 * @author hobart
 */
public interface Car{  
	public abstract  void drive();	
}
/**
 * 具体产品  Bmw
 * @author hobart
 */
public class Bmw implements Car {
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}	
	public void drive(){
		System.out.println(this.getName()+"车----已启动-----------------");  
	}
}
/**
 * 具体产品  Benz
 * @author hobart
 */
public class Benz implements Car {
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}	
	public void drive(){
		System.out.println(this.getName()+"车----已启动-----------------");  
	}
}
/**
 * 抽象产品 Audi
 * @author hobart
 */
public class Audi implements Car {
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}	
	public void drive(){
		System.out.println(this.getName()+"车----已启动-----------------");  
	}
}
/**
 * 抽象工厂
 * @author hobart
 */
public abstract class DriveAbstractFactory {
	public abstract Benz createBenzCar(String car);
	public abstract Bmw createBmwCar(String car);
	public abstract Audi createAudiCar(String car);
}
/**
 * 具体工厂 BmwDriverAbstractFactory(每个具体工厂负责一个具体产品) 
 * @author hobart
 */
public class BmwDriveAbstractFactory extends DriveAbstractFactory {
	@Override
	public Bmw createBmwCar(String car) {
		Bmw bmw = new Bmw();
		bmw.setName(car);
		return bmw; 
	}
	@Override
	public Benz createBenzCar(String car) {
		return null;
	}
	@Override
	public Audi createAudiCar(String car) {
		return null;
	}
}
/**
 * 具体工厂 BenzDriverAbstractFactory(每个具体工厂负责一个具体产品) 
 * @author hobart
 */
public class BenzDriveAbstractFactory extends DriveAbstractFactory {
	@Override
	public Benz createBenzCar(String car) {
		Benz benz = new Benz();
		benz.setName(car);
		return benz; 
	}
	@Override
	public Bmw createBmwCar(String car) {
		return null;
	}
	@Override
	public Audi createAudiCar(String car) {
		return null;
	}
}
/**
 * 具体工厂 AudiDriverAbstractFactory(每个具体工厂负责一个具体产品) 
 * @author hobart
 */
public class AudiDriveAbstractFactory extends DriveAbstractFactory {
	@Override
	public Benz createBenzCar(String car) {
		return null;
	}
	@Override
	public Bmw createBmwCar(String car) {
		return null;
	}
	@Override
	public Audi createAudiCar(String car) {
		Audi audi = new Audi();
		audi.setName(car);
		return audi; 
	}
}
/**
 * 创建工厂的工厂 CarFactory(创建一个具体的工厂) 
 * @author hobart
 */
public class CarFactory {
	public static  DriveAbstractFactory driverAbstractFactory = null;
	public static DriveAbstractFactory getFactory(String context) {
		if(context.equalsIgnoreCase("bmw")) {
			return new BmwDriveAbstractFactory();
		} else if(context.equalsIgnoreCase("benz")) {
			return new BenzDriveAbstractFactory();
		} else if(context.equalsIgnoreCase("audi")) {
			return new AudiDriveAbstractFactory();
		} else {
			return null;
		}
	}
}
/**
 * 测试
 * @author hobart
 */
public class DriveTest {
	public static void main(String[] args) {
		//获取car工厂
	    DriveAbstractFactory driveAbstractFactory = CarFactory.getFactory("BENZ");
	    //获取形状为 Benz 的对象
	    Benz benz = driveAbstractFactory.createBenzCar("BENZ");
	    //调用 Benz 的 drive 方法
	    benz.drive();

	    //获取car工厂
	    DriveAbstractFactory BmwDriveAbstractFactory = CarFactory.getFactory("BMW");
	    //获取形状为 Bmw 的对象
	    Bmw bmw = BmwDriveAbstractFactory.createBmwCar("BMW");
	    //调用 Benz 的 drive 方法
	    bmw.drive();
	}
}

UML图

抽象工厂

优点:
首先是满足OCP的,而且可以满足产品切换,能实现的前提是比如A和B两个产品,它们有1和2两个方法接口(类),现在我们在增加新的产品C(假设也是只有1和2两个方法接口),我们要做的只是增加一个产品类再增加一个工厂类就行了,如果是简单工厂或者是工厂方法的的话通常都是增加两个算法类C.1,C.2,简单工厂需要修改switch增加两个语句,工厂方法是在增加两个工厂类。可见抽象工厂的优点。

缺点:
显而易见,太重了。

总括:

简单工厂: 工厂类中,根据条件决定一个接口由哪个具体产品类来实现。

工厂方法: 创建多个工厂类。各个工厂类中,都对应一个获得接口A实例的方法。用户决定使用哪个工厂。

抽象工厂: 对工厂方法进行扩展。各个工厂类中,再增加一个获得接口B实例的方法。

从对象的角度来看:

  1. 简单工厂是一对多的关系 (一个工厂可以生成多个产品)
  2. 工厂方法是一对一的关系(一个工厂只能生产一个产品)
  3. 抽象工厂抽象了前面两个设计模式、(一生产线可以生产多个产品可以、多个生产线可以生产一个产品)

对比:
简单工厂实现简单,扩展也很容易,但是不满足OCP,不满足OCP的代价就是难维护,在维护的时候容易引发新的BUG,相比之下,工厂方法则是把对象的实例化延迟到了继承的子类里面,这样可以量或的扩展工厂。扩展的是时候满足OCP,但是不支持产品切换,也就是只能满足一层的产品(算法)抽象,而抽象工厂则是继续把产品进行再次抽象,最后得到一个可以支持产品切换的结构,但问题是太重了,过于复杂,不过还好,很多支持反射的语言,我们可以直接通过反射技术来优化这个“过重”的缺点。当然,也可以用反射来优化前面两个工厂结构(但是抽象工厂和工厂方法相比,两者也都只是支持一个地方的可扩展而已,不要误解为抽象工厂可以扩展两个地方)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漏墨小子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值