简单工厂、工厂方法模式、抽象工厂模式

作者: 激情的狼王 | 来源:发表于2017-12-12 15:11 被阅读0次

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

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

    这三种模式从上到下逐步抽象,并且更具一般性。还有一种分类法,就是将简单工厂模式看为工厂方法模式的一种特例,两个归为一类。两者皆可,这本为使用《Java与模式》的分类方法。

    在什么样的情况下我们应该记得使用工厂模式呢?大体有两点:

    1.在编码时不能预见需要创建哪种类的实例。
    2.系统不应依赖于产品类实例如何被创建、组合和表达的细节

    一、简单工厂模式
    这个模式本身很简单而且使用在业务较简单的情况下。一般用于小项目或者具体产品很少扩展的情况(这样工厂类才不用经常更改)。
    它由三种角色组成:

    工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,根据逻辑不同,产生具体的工厂产品。如例子中的Driver类。
    抽象产品角色:它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。如例中的Car接口。
    具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现,如例子中的Benz、Bmw类。

    //抽象产品  
    abstract class Car{  
        private String name;  
          
        public abstract void drive();  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    //具体产品  
    class Benz extends Car{  
        public void drive(){  
            System.out.println(this.getName()+"----go-----------------------");  
        }  
    }  
      
    class Bmw extends Car{  
        public void drive(){  
            System.out.println(this.getName()+"----go-----------------------");  
        }  
    }  
      
    //简单工厂  
    class Driver{  
        public static Car createCar(String car){  
            Car c = null;  
            if("Benz".equalsIgnoreCase(car))  
                c = new Benz();  
            else if("Bmw".equalsIgnoreCase(car))  
                c = new Bmw();  
            return c;  
        }  
    }  
      
    //main方法  
    public class BossSimplyFactory {  
      
        public static void main(String[] args) throws IOException {  
            Car car = Driver.createCar("benz");  
            car.setName("benz");  
            car.drive();  
        }  
    

    这便是简单工厂模式了。那么它带了了什么好处呢?
    首先,符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责“消费”产品。
    下面我们从开闭原则上来分析下简单工厂模式。当增加了一辆车的时候,只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。(即创建一个新的车类,继承抽象产品Car)那么 对于产品部分来说,它是符合开闭原则的——对扩展开放、对修改关闭;但是工厂类不太理想,因为每增加一辆车,都要在工厂类中增加相应的商业逻辑和判 断逻辑,这显自然是违背开闭原则的。
    正如我前面提到的简单工厂模式适用于业务简单的情况下或者具体产品很少增加的情况。而对于复杂的业务环境可能不太适应了。这就应该由工厂方法模式来出场了!!
    二、工厂方法模式
    它由四种角色组成:

    抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
    具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
    抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
    具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

    //抽象产品  
    abstract class Car{  
        private String name;  
          
        public abstract void drive();  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    //具体产品  
    class Benz extends Car{  
        public void drive(){  
            System.out.println(this.getName()+"----go-----------------------");  
        }  
    }  
    class Bmw extends Car{  
        public void drive(){  
            System.out.println(this.getName()+"----go-----------------------");  
        }  
    }  
      
      
    //抽象工厂  
    abstract class Driver{  
        public abstract Car createCar(String car) throws Exception;  
    }  
    //具体工厂(每个具体工厂负责一个具体产品)  
    class BenzDriver extends Driver{  
        public Car createCar(String car) throws Exception {  
            return new Benz();  
        }  
    }  
    class BmwDriver extends Driver{  
        public Car createCar(String car) throws Exception {  
            return new Bmw();  
        }  
    }  
      
    public class Boss{ 
        public static void main(String[] args) throws Exception {  
            Driver d = new BenzDriver();  
            Car c = d.createCar("benz");   
            c.setName("benz");  
            c.drive();  
        }  
    }  
    

    使用开闭原则来分析下工厂方法模式。当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。(即当有新产品时,只要创建并基础抽象产品;新建具体工厂继承抽象工厂;而不用修改任何一个类)工厂方法模式是完全符合开闭原则的!
    使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。
    当然特殊的情况,就要特殊对待了:对于系统中存在不同的产品树,而且产品树上存在产品族(下一节将解释这个名词)。那么这种情况下就可能可以使用抽象工厂模式了。

    三、抽象工厂模式
    先来认识下什么是产品族: 位于不同产品等级结构中,功能相关联的产品组成的家族。

    BmwCar和BenzCar就是两个产品树(产品层次结构);而BenzSportsCar和BmwSportsCar就是一个产品族。他们都可以放到跑车家族中,因此功能有所关联。同理BmwBussinessCar和BenzBusinessCar也是一个产品族。

    可以这么说,它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。
    而且使用抽象工厂模式还要满足一下条件:

    1.系统中有多个产品族,而系统一次只可能消费其中一族产品
    2.同属于同一个产品族的产品以其使用。

    来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):

    抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
    具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
    抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
    具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

    //抽象产品(Bmw和Audi同理)  
    abstract class BenzCar{  
        private String name;  
          
        public abstract void drive();  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    //具体产品(Bmw和Audi同理)  
    class BenzSportCar extends BenzCar{  
        public void drive(){  
            System.out.println(this.getName()+"----BenzSportCar-----------------------");  
        }  
    }  
    class BenzBusinessCar extends BenzCar{  
        public void drive(){  
            System.out.println(this.getName()+"----BenzBusinessCar-----------------------");  
        }  
    }  
      
    abstract class BmwCar{  
        private String name;  
          
        public abstract void drive();  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    class BmwSportCar extends BmwCar{  
        public void drive(){  
            System.out.println(this.getName()+"----BmwSportCar-----------------------");  
        }  
    }  
    class BmwBusinessCar extends BmwCar{  
        public void drive(){  
            System.out.println(this.getName()+"----BmwBusinessCar-----------------------");  
        }  
    }  
      
    abstract class AudiCar{  
        private String name;  
          
        public abstract void drive();  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    class AudiSportCar extends AudiCar{  
        public void drive(){  
            System.out.println(this.getName()+"----AudiSportCar-----------------------");  
        }  
    }  
    class AudiBusinessCar extends AudiCar{  
        public void drive(){  
            System.out.println(this.getName()+"----AudiBusinessCar-----------------------");  
        }  
    }  
      
      
    //抽象工厂  
    abstract class Driver3{  
        public abstract BenzCar createBenzCar(String car) throws Exception;  
          
        public abstract BmwCar createBmwCar(String car) throws Exception;  
          
        public abstract AudiCar createAudiCar(String car) throws Exception;  
    }  
    //具体工厂  
    class SportDriver extends Driver3{  
        public BenzCar createBenzCar(String car) throws Exception {  
            return new BenzSportCar();  
        }  
        public BmwCar createBmwCar(String car) throws Exception {  
            return new BmwSportCar();  
        }  
        public AudiCar createAudiCar(String car) throws Exception {  
            return new AudiSportCar();  
        }  
    }  
    class BusinessDriver extends Driver3{  
        public BenzCar createBenzCar(String car) throws Exception {  
            return new BenzBusinessCar();  
        }  
        public BmwCar createBmwCar(String car) throws Exception {  
            return new BmwBusinessCar();  
        }  
        public AudiCar createAudiCar(String car) throws Exception {  
            return new AudiBusinessCar();  
        }  
    }  
      
    public class BossAbstractFactory {  
      
        public static void main(String[] args) throws Exception {    
            Driver3 d = new BusinessDriver();  
            AudiCar car = d.createAudiCar("");  
            car.drive();  
        }  
    }  
    

    其中:BenzSportCar和BenzBusinessCar属于产品树;同理BmwSportCar和BmwBusinessCar。而BenzSportCar和BmwSportCar和AudiSportCar属于产品族。
    所以抽象工厂模式一般用于具有产品树和产品族的场景下。
    抽象工厂模式的缺点:如果需要增加新的产品树,那么就要新增三个产品类,比如VolvoCar,VolvoSportCar,VolvoSportCar,并且要修改三个工厂类。这样大批量的改动是很丑陋的做法。
    所以可以用简单工厂配合反射来改进抽象工厂:

    abstract class BenzCar{  
        private String name;  
          
        public abstract void drive();  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    class BenzSportCar extends BenzCar{  
        public void drive(){  
            System.out.println(this.getName()+"----BenzSportCar-----------------------");  
        }  
    }  
    class BenzBusinessCar extends BenzCar{  
        public void drive(){  
            System.out.println(this.getName()+"----BenzBusinessCar-----------------------");  
        }  
    }  
      
    abstract class BmwCar{  
        private String name;  
          
        public abstract void drive();  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    class BmwSportCar extends BmwCar{  
        public void drive(){  
            System.out.println(this.getName()+"----BmwSportCar-----------------------");  
        }  
    }  
    class BmwBusinessCar extends BmwCar{  
        public void drive(){  
            System.out.println(this.getName()+"----BmwBusinessCar-----------------------");  
        }  
    }  
      
    abstract class AudiCar{  
        private String name;  
          
        public abstract void drive();  
          
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    class AudiSportCar extends AudiCar{  
        public void drive(){  
            System.out.println(this.getName()+"----AudiSportCar-----------------------");  
        }  
    }  
    class AudiBusinessCar extends AudiCar{  
        public void drive(){  
            System.out.println(this.getName()+"----AudiBusinessCar-----------------------");  
        }  
    }  
      
      
    /** 
     * 简单工厂通过反射改进抽象工厂及其子工厂 
     * @author Administrator 
     * 
     */  
    class Driver3{  
        public static BenzCar createBenzCar(String car) throws Exception {  
            return (BenzCar) Class.forName(car).newInstance();  
        }  
          
        public static BmwCar createBmwCar(String car) throws Exception {  
            return (BmwCar) Class.forName(car).newInstance();  
        }  
          
        public static AudiCar createAudiCar(String car) throws Exception {  
            return (AudiCar) Class.forName(car).newInstance();  
        }  
    }  
    //客户端  
    public class SimpleAndAbstractFactory {  
      
        public static void main(String[] args) throws Exception {  
      
            AudiCar car = Driver3.createAudiCar("com.java.pattendesign.factory.AudiSportCar");  
            car.drive();  
        }  
    }  
    

    相关文章

      网友评论

        本文标题:简单工厂、工厂方法模式、抽象工厂模式

        本文链接:https://www.haomeiwen.com/subject/dmwgixtx.html