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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值