Java设计模式之工厂模式

工厂模式

认识工厂模式

所有的工厂模式都用来封装对象的创建。工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象

是什么,来达到将对象的创过封装的目的。

简单工厂

定义

以下引用自**《head first 设计模式》**书中对简单工厂的描述

简单工厂其实不是一个设计模式,反而比较像是- -种编程习惯。

但由于经常被使用,所以我们给它一一个"Head First Pattern荣誉奖"。

有些开发人员的确是把这个编程习惯误认为是“工厂模式”(Factory Pattern) 。

当你下次和另一个开发人员之间无话可说的时候,这应当是打破沉默的一个不错的话题。

使用场景

以下引用来自文末参考1

对于产品种类相对较少的情况,考虑使用简单工厂模式。

使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。

优点和缺点

以下引用来自文末参考1

优点:
  1. 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
  2. 客户端无需知道所创建具体产品的类名,只需知道参数即可。
  3. 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。
缺点:
  1. 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
  2. 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
  3. 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
  4. 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。

一个简单工厂–披萨工厂的实现

以下代码来自《head first 设计模式》实例

具体的Pizza通过构造函数产生

public class ClamPizza extends Pizza {
   public ClamPizza() {
      name = "Clam Pizza";
      dough = "Thin crust";
      sauce = "White garlic sauce";
      toppings.add("Clams");
      toppings.add("Grated parmesan cheese");
   }
}
public class SimplePizzaFactory {
   //根据不同情况产生不同的pizza对象
   public Pizza createPizza(String type) {
      Pizza pizza = null;

      if (type.equals("cheese")) {
         pizza = new CheesePizza();
      } else if (type.equals("pepperoni")) {
         pizza = new PepperoniPizza();
      } else if (type.equals("clam")) {
         pizza = new ClamPizza();
      } else if (type.equals("veggie")) {
         pizza = new VeggiePizza();
      }
      return pizza;
   }
}

以上代码中CheesePizza,PepperoniPizza,VeggiePizza都有一个相同的父类

abstract public class Pizza {
   String name;
   String dough;
   String sauce;
   List<String> toppings = new ArrayList<String>();

   public String getName() {
      return name;
   }

   public void prepare() {
      System.out.println("Preparing " + name);
   }

   public void bake() {
      System.out.println("Baking " + name);
   }

   public void cut() {
      System.out.println("Cutting " + name);
   }

   public void box() {
      System.out.println("Boxing " + name);
   }

   @Override
   public String toString() {
      // code to display pizza name and ingredients
      StringBuffer display = new StringBuffer();
      display.append("---- " + name + " ----\n");
      display.append(dough + "\n");
      display.append(sauce + "\n");
      for (String topping : toppings) {
         display.append(topping + "\n");
      }
      return display.toString();
   }
}

使用SimplePizzaFactory生产对象

public class PizzaStore {
   SimplePizzaFactory factory;
 
   public PizzaStore(SimplePizzaFactory factory) { 
      this.factory = factory;
   }
   //处理订单,生产pizza 在PizzaStore中完成
   public Pizza orderPizza(String type) {
      Pizza pizza;
 
      pizza = factory.createPizza(type);
 
      pizza.prepare();
      pizza.bake();
      pizza.cut();
      pizza.box();

      return pizza;
   }

}

工厂方法模式

定义

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟

到子类。

区别

简单工厂把全部的事情,在一个地方都处理完了,然而工厂方法却是创建一个框架,让子类决定要如何实现。

比方说,在工厂方法中,orderPizza()方 法提供了一-般的框架,以便创建比萨,orderPizza()方 法依赖工厂方

法创建具体类,并制造出实际的比萨。可通过继承PizzaStore类,决定实际制造出的比萨是什么。简单工厂的

做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的

产品。

使用场景

以下引用来自文末参考2

  • 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
  • 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
  • 客户不关心创建产品的细节,只关心产品的品牌

优点和缺点

以下引用来自文末参考2

优点:
  • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
  • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
  • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
  • 类的个数容易过多,增加复杂度
  • 增加了系统的抽象性和理解难度
  • 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

实现

以下代码来自《head first 设计模式》实例

public class NYStyleCheesePizza extends Pizza {

	public NYStyleCheesePizza() { 
		name = "NY Style Sauce and Cheese Pizza";
		dough = "Thin Crust Dough";
		sauce = "Marinara Sauce";
 
		toppings.add("Grated Reggiano Cheese");
	}
}

PizzaStore不决定具体的披萨类型。由其子类决定

public abstract class PizzaStore {
 
   protected abstract Pizza createPizza(String item);
 
   public Pizza orderPizza(String type) {
      Pizza pizza = createPizza(type);
      System.out.println("--- Making a " + pizza.getName() + " ---");
      pizza.prepare();
      pizza.bake();
      pizza.cut();
      pizza.box();
      return pizza;
   }
}

PizzaStore的子类NYPizzaStore

public class NYPizzaStore extends PizzaStore {

	@Override
	Pizza createPizza(String item) {
		if (item.equals("cheese")) {
			return new NYStyleCheesePizza();
		} else if (item.equals("veggie")) {
			return new NYStyleVeggiePizza();
		} else if (item.equals("clam")) {
			return new NYStyleClamPizza();
		} else if (item.equals("pepperoni")) {
			return new NYStylePepperoniPizza();
		} else {
			return null;
		}
	}
}

抽象工厂

定义

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

抽象工厂允许客户使用抽象的接口来创建-组相关的产品,而不需要知道(或关心)实际产出的具体产品是什么。

这样一来,客户就从具体的产品中被解耦。

抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族

区别

工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动

物又种植物,电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。

使用场景

以下引用来自文末参考3

抽象工厂模式通常适用于以下场景:

  1. 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  2. 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  3. 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

优点和缺点

以下引用来自文末参考3

抽象工厂模式除了具有工厂方法模式的优点外,其他主要优点如下。

  • 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
  • 当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。
  • 抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。

其缺点是:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。

实现

以下代码来自《head first 设计模式》实例

ClamPizza不是通过传入一个工厂出产生

一个工厂的接口:

public interface PizzaIngredientFactory {
 
   public Dough createDough();
   public Sauce createSauce();
   public Cheese createCheese();
   public Veggies[] createVeggies();
   public Pepperoni createPepperoni();
   public Clams createClam();
 
}
public class ClamPizza extends Pizza {
   PizzaIngredientFactory ingredientFactory;
 
   public ClamPizza(PizzaIngredientFactory ingredientFactory) {
      this.ingredientFactory = ingredientFactory;
   }
 
   @Override
   void prepare() {
      System.out.println("Preparing " + name);
      dough = ingredientFactory.createDough();
      sauce = ingredientFactory.createSauce();
      cheese = ingredientFactory.createCheese();
      clam = ingredientFactory.createClam();
   }
}

定义一个抽象的(abstract)PizzaStore

public abstract class PizzaStore {
 
	abstract Pizza createPizza(String item);
 
	public Pizza orderPizza(String type) {
		Pizza pizza = createPizza(type);
		System.out.println("--- Making a " + pizza.getName() + " ---");
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		return pizza;
	}
}

实现接口的具体工厂:

public class ChicagoPizzaIngredientFactory 
   implements PizzaIngredientFactory 
{

   @Override
   public Dough createDough() {
      return new ThickCrustDough();
   }

   @Override
   public Sauce createSauce() {
      return new PlumTomatoSauce();
   }

   @Override
   public Cheese createCheese() {
      return new MozzarellaCheese();
   }

   @Override
   public Veggies[] createVeggies() {
      Veggies veggies[] = { new BlackOlives(), 
                            new Spinach(), 
                            new Eggplant() };
      return veggies;
   }

   @Override
   public Pepperoni createPepperoni() {
      return new SlicedPepperoni();
   }

   @Override
   public Clams createClam() {
      return new FrozenClams();
   }
}

使用具体工厂来定义ChicagoPizzaStore

public class ChicagoPizzaStore extends PizzaStore {

	@Override
    protected Pizza createPizza(String item) {
		Pizza pizza = null;
		PizzaIngredientFactory ingredientFactory =
		new ChicagoPizzaIngredientFactory();

		if (item.equals("cheese")) {

			pizza = new CheesePizza(ingredientFactory);
			pizza.setName("Chicago Style Cheese Pizza");

		} else if (item.equals("veggie")) {

			pizza = new VeggiePizza(ingredientFactory);
			pizza.setName("Chicago Style Veggie Pizza");

		} else if (item.equals("clam")) {

			pizza = new ClamPizza(ingredientFactory);
			pizza.setName("Chicago Style Clam Pizza");

		} else if (item.equals("pepperoni")) {

			pizza = new PepperoniPizza(ingredientFactory);
			pizza.setName("Chicago Style Pepperoni Pizza");

		}
		return pizza;
	}
}
public class PizzaTestDrive {
 
   public static void main(String[] args) {
      PizzaStore nyStore = new NYPizzaStore();
      PizzaStore chicagoStore = new ChicagoPizzaStore();
 
      Pizza pizza = nyStore.orderPizza("cheese");
      System.out.println("Ethan ordered a " + pizza + "\n");
 
      pizza = chicagoStore.orderPizza("cheese");
      System.out.println("Joel ordered a " + pizza + "\n");

      pizza = nyStore.orderPizza("clam");
      System.out.println("Ethan ordered a " + pizza + "\n");
 
      pizza = chicagoStore.orderPizza("clam");
      System.out.println("Joel ordered a " + pizza + "\n");

      pizza = nyStore.orderPizza("pepperoni");
      System.out.println("Ethan ordered a " + pizza + "\n");
 
      pizza = chicagoStore.orderPizza("pepperoni");
      System.out.println("Joel ordered a " + pizza + "\n");

      pizza = nyStore.orderPizza("veggie");
      System.out.println("Ethan ordered a " + pizza + "\n");
 
      pizza = chicagoStore.orderPizza("veggie");
      System.out.println("Joel ordered a " + pizza + "\n");
   }
}

参考

1简单工厂模式

2工厂方法模式(详解版)

3抽象工厂模式(详解版)

4 工厂模式案例详解

5《head first 设计模式》

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java 线程池工厂类是一种构建线程池的工具类,其通过提供线程池配置参数来构造线程池对象。通常来说,线程池工厂类会提供一些静态方法,用于创建不同类型的线程池,如单线程池、固定大小的线程池、可扩展的线程池等。 Java 标准库中提供了 `Executors` 类作为线程池工厂类。例如,你可以使用以下代码创建一个固定大小的线程池: ``` ExecutorService executor = Executors.newFixedThreadPool(5); ``` 这里的 `executor` 就是线程池对象。你也可以使用以下代码创建一个单线程的线程池: ``` ExecutorService executor = Executors.newSingleThreadExecutor(); ``` 另外,Java 还提供了一个 `ThreadPoolExecutor` 类来提供更多细节的线程池定制能力。你可以使用 `ThreadPoolExecutor` 类的构造函数来创建线程池,并通过指定线程池的配置参数来控制线程池的行为。 总的来说,线程池工厂类是一种方便的工具,可以帮助你快速构建线程池,并且提供了多种选择,以满足不同的需求。 ### 回答2: Java线程池工厂类是一个用于创建和管理线程池的类。它提供了一种方便的方式来创建和重用线程,从而实现线程的高效使用。 在Java中,线程池是一种管理和控制线程的机制,它可以将任务提交给线程执行,而不是每次都创建新的线程。这种方式避免了频繁地创建和销毁线程的开销,提高了系统的性能和响应速度。 Java线程池工厂类通过提供一系列静态方法来创建不同类型的线程池,比如FixedThreadPool,CachedThreadPool和ScheduledThreadPool等。这些方法返回一个实现了ExecutorService接口的线程池对象,通过这个对象可以管理线程池的状态和操作。 线程池工厂类的创建线程池的方法通常包含一些参数,比如核心线程数、最大线程数、线程空闲时间、任务队列等,通过这些参数可以灵活地配置线程池以满足具体的业务需求。 线程池工厂类还提供了一些管理线程池的方法,比如提交任务、关闭线程池、获取线程池状态等。通过这些方法可以方便地向线程池提交任务,并且在需要的时候可以优雅地关闭线程池。 总之,Java线程池工厂类是一个非常重要的类,它提供了一种简单且高效的方式来管理和重用线程,有助于提高系统的性能和可扩展性。 ### 回答3: Java线程池工厂类是用来创建和管理线程池的类。线程池可以有效地管理线程的创建和销毁,提高程序的效率和性能。 在Java中,可以使用ThreadPoolExecutor类来创建线程池。线程池工厂类是为线程池的创建和配置提供便捷方法的工具类。它可以根据需要返回不同类型的线程池,比如固定大小的线程池、缓存线程池或定时任务线程池。 线程池工厂类提供了一系列的静态方法,可以根据预定义的参数来创建线程池。比如,可以通过指定线程池的最小和最大线程数、线程的空闲时间等参数来创建一个固定大小的线程池。也可以通过设置线程池的最大线程数为无限大,来创建一个缓存线程池。 除了创建线程池,线程池工厂类还提供了一些其他的方法,用于执行任务或关闭线程池。可以通过submit()方法将任务提交给线程池执行,也可以通过shutdown()方法关闭线程池,停止所有线程的执行。 总的来说,Java线程池工厂类是一个方便的工具类,可以用于创建和管理线程池。通过使用线程池工厂类,可以避免手动创建和管理线程的繁琐工作,提高程序的可维护性和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值