Java设计模式之工厂模式

Java设计模式:工厂(Factory)模式

1.问题分析

  • 首先,给出一个不够合理的披萨店设计

      public class OldStore {
      	Pizza orderPizza(){
      		Pizza pizza = new Pizza();
      		pizza.prepare(); 
      		pizza.bake(); 
      		pizza.cut();
      		pizza.box(); 
      		return pizza; 
      	}
      }
    
  • 如果我们需要更多不同种类的pizza,那么我们就要增加代码来确定pizza的类型,然后才能制造pizza,那么,披萨店的设计代码就可能变成下面这样:

      public class OldStore {
      	Pizza orderPizza(String type){
      		Pizza pizza = new Pizza();
      		//-----不停变化的部分-----
      		if(type.equals("cheese")){
      			pizza = new ChessePizza();
      		} else if (type.equals(”greek”)) { 
      			pizza = new GreekPizza(); 
      		} else if (type.equals(”other”)) { 
      			//other type
      		}
      		//----------------------
      		pizza.prepare(); 
      		pizza.bake(); 
      		pizza.cut();
      		pizza.box(); 
      		return pizza; 
      	}
      }
    

我们可以发现,如果要增加不同的种类,那么,我们就必须去修改oderPizza()方法里的代码,这样,oderPizza()无法对修改关闭,所以我们需要进一步使用封装。下面给出三种类型的工厂模式。


2.简单工厂

  • 如果需要让oderPizza()方法对修改关闭,我们应该如何设计呢?那便是将不停变化的部分,即确定披萨类型的部分抽离出来,放到另一个类里,如SimplePizzaFactory,OldStore类只需要负责从SimplePizzaFactory里获取披萨,然后进行后续操作即可。

      public class SimplePizzaFactroy {
      	public Pizza createPizza(String type) { 
      		Pizza pizza = null;
      		if (type.equals(”cheese”)) { 
      			pizza = new CheesePizza();
      		} else if (type.equals(”greek”)) { 
      			pizza = new GreekPizza();
      		} else if (type.equals(”other”)) { 
      			// other type. 
      		}
      		return pizza;
      	}
      }
    
  • 对应的,将OldStore重做为PizzaStore类,代码如下:

      public class PizzaStore { 
      	SimplePizzaFactory factory; //加入一个对SimplePizzaFactory的引用
      	//构造需要一个工厂作为参数 
      	public PizzaStore(SimplePizzaFactory factory) { 
      		this.factory = factory; 
      	}
      	public Pizza orderPizza(String type) { 
      		Pizza pizza;
      		//该方法通过简单传入订单类型来使用工厂创建披萨
      		pizza = factory.createPizza(type); // new操作符被换为工厂对象创建方法
      		pizza.prepare(); 
      		pizza.bake(); 
      		pizza.cut();
      		pizza.box(); 
      		return pizza; 
      	}
      }
    

3.工厂方法

  • 加盟披萨店 要求披萨店的各个加盟店能够提供不同风味的披萨,并复用代码,以使得披萨的 流程能够一致不变。利用 SimplePizzaFactory 的一般实现如下:

      NYPizzaFactory nyFactory = new NYPizzaFactory();
      PizzaStore nyStore = new PizzaStore(nyFactory);
      nyStore.orderPizza(”Veggie”) ;
      ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory(); 
      PizzaStore nyStore = new PizzaStore(chicagoFactory); 
      nyStore.orderPizza(”Veggie”) ;
    

即以SimplePizzaFactory为父类,派生不同的工厂类。当我们希望能够建立一个框架,把加盟店和创建披萨捆绑在一起,保持披萨的质量控制,同时使得代码具有一定的弹性。我们应该怎么做呢?

  • 给披萨店使用的框架采用如下框架可以使得披萨制作活动局限于 PizzaStore 类,而同时又能 让这些加盟店依然可以自由的制作该区域的风味。

      public abstract class PizzaStore {
      	public Pizza OrderPizza(String type) { 
      		Pizza pizza;
      		// createPizza()方法从工厂对象中回到PizzaStore
      		pizza = createPizza(type);
      		pizza.prepare(); 
      		pizza.bake(); 
      		pizza.cut();
      		pizza.box(); 
      		return pizza; 
      	}		
      	// PizzaStore里的工厂方法是抽象的 
      	abstract Pizza createPizza(String type); 
      }
    

我们可以看到,我们将原本放在工厂中实现的创建pizza操作,放回到了PizzaStore里,我们现在只需要以PizzaStore为父类,让每个区域的不同pizza店继承,各自实现createPizza()方法就行。createPizza() 方法是个抽象方法,所有任何具体的加盟店必须实现这个方法,从而个性化加盟 店的披萨风味。例如,NYPPizzaStore的实现。

	public class NYPizzaStore extends PizzaStore {
		@Override 
		Pizza createPizza(String type) {
			if (type.equals(”cheese”)) {
				return new NYStyleCheesePizza(); 
			} else if (type.equals(”veggie”)) {
				return new NYStyleVeggiePizza(); 
			} else if (type.equals(”other”)) { 
				// other type. 
			} else 
				return null; 
		}
	}
  • 原来是在简单工厂中是由一个对象负责所有具体类的实例化,现在通过对 PizzaStore 作改变,使得由一群子类来负责实例化。 工厂方法用来处理对象的创建,并将这样的行为封装在子类中,这样客户程序中关于超类的 代码就和子类对象创建代码解耦。
  • 工厂方法是抽象
  • 工厂方法必须返回一个产品,超类中定义的方法,通常会用到工厂方法的返回值
  • 工厂方法将客户(即超类中的代码,如 orderPizza())和实际创建具体产品的代码分隔开。

4.抽象工厂

  • 工厂方法模式从设计角度考虑存在一定的问题:类的创建依赖工厂类。也就是说,如果想要 拓展程序,必须对工厂类进行修改,这违背了闭包原则。 所以,可以使用抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的 工厂类就可以了,不需要修改之前的代码。参考示例的4.3类图,该示例包含一个消息发送者接口 (Sender) 和一个抽象工厂接口(Provider)。

    相关代码如下:

    File: Sender.java

      package ouc.cs.course.java.test.abstractfactory;
      public interface Sender { 
      	public void Send(); 
      }
    

    File: Provider.java

      package ouc.cs.course.java.test.abstractfactory;
      public interface Provider { 
      	public Sender produce(); 
      }
    

    File: MailSender.java

      package ouc.cs.course.java.test.abstractfactory;
      public class MailSender implements Sender {
      	public void Send() {
      		System.out.println(”this is mailsender!”); 
      	}
      }
    

    File: SmsSender.java

      package ouc.cs.course.java.test.abstractfactory;
      public class SmsSender implements Sender {
      	public void Send() {
      		System.out.println(”this is smssender!”); 
      	}
      }
    

    File: SendMailFactory.java

      package ouc.cs.course.java.test.abstractfactory;
      public class SendMailFactory implements Provider {
      	@Override
      	public Sender produce() { 
      		return new MailSender(); 
      	}
      }
    

    File: SendSmsFactory.java

      package ouc.cs.course.java.test.abstractfactory;
      public class SendSmsFactory implements Provider {
      	@Override
      	public Sender produce() { 
      		return new SmsSender(); 
      	}
      }
    

    File: Test.java

      package test.abstractfactory;
      import ouc.cs.course.java.test.abstractfactory.Provider; 
      import ouc.cs.course.java.test.abstractfactory.SendMailFactory; 
      import ouc.cs.course.java.test.abstractfactory.Sender;
      
      public class Test { 
      	public static void main(String[] args) { 
      		Provider provider = new SendMailFactory(); 
      		Sender sender = provider.produce(); 
      		sender.Send(); 
      	}
      }
    

当你想要扩展产品种类时,只需要增加对应的工厂类和产品类即可,比如我要增加一个QQSender类,只需要新建一个QQSender类实现Sender接口和SendQQFactory类实现Provider接口即可扩展产品种类。

原文地址:https://www.cnblogs.com/FZfangzheng/p/7732381.html