• 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接口即可扩展产品种类。

  • 相关阅读:
    Java异常处理和设计
    一次qps测试实践
    Alternate Task UVA
    Just Another Problem UVA
    Lattice Point or Not UVA
    Play with Floor and Ceil UVA
    Exploring Pyramids UVALive
    Cheerleaders UVA
    Triangle Counting UVA
    Square Numbers UVA
  • 原文地址:https://www.cnblogs.com/FZfangzheng/p/7732381.html
Copyright © 2020-2023  润新知