设计模式之-工厂模式

288 阅读7分钟

1.简单工厂模式

​ 简单工厂模式(Simple Factory Pattren)是指由一个工厂对象决定创建哪一种产品的实例。简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数。对于如何创建对象不需要关心。也就是对不同类的对象进行了一次简简单单的封装,我们只需要想这个类传入相应的参数去调用对象即可。

  • 例:

    场景:假设我们有一个生产自行车的工厂,其中我们会生产诸如山地车、公路车、儿童自行车等等。在未采用工厂模式之前我们的代码实现可能如下边。

    这里我们可以定义一个自行车接口:

    public interface Bike {
        public void run();
    }
    

    定义一个山地车的实现类:

    public class MountainBike implements Bike {
        @Override
        public void run() {
            System.out.println("我在骑山地车哟!");
        }
    }
    

    编写客户端的调用代码:

    public class SimpleFactoryMain {
        public static void main(String[] args) {
            Bike cycle = new MountainBike();
            cycle.run();
        }
    }
    

在上面的代码中,父类Bike指向子类MountainBike的引用,客户端的调用代码依赖MountainBike,如果我们的业务越来越多,继续增加车的种类,那岂不是代码会变得越来越臃肿,实现类可能会变成下面这样:

        Bike bike1 = new Bike1();
        bike1.run();

        Bike bike2 = new Bike2();
        bike2.run();

        Bike bike3 = new Bike3();
        bike3.run();
        
        ......
        ......

现在我们要想办法解决这种依赖,把创建的细节隐藏起来。现在我们简单工厂模式来解决这个问题。

基于上面的自行车接口,增加公路车类RoadBike:

public class RoadBike implements Bike {
    @Override
    public void run() {
        System.out.println("我再骑公路自行车!");
    }
}

创建工厂类BikeFactory:

public class BikeFactory {
    public Bike create(String name) {
        if ("MountainBike".equals(name)) {
            return new MountainBike();
        } else if ("Roadbike".equals(name)) {
            return new RoadBike();
        } else {
            return null;
        }
    }
}

修改客户端的实现代码如下:

public class SimpleFactoryMain {
    public static void main(String[] args) {
        BikeFactory bikeFactory = new BikeFactory();
        bikeFactory.create("Roadbike");
    }
}

客户端实现变简单了,但是如果我们要继续增加自行车的种类,那么每次增加产品都要修改代码的逻辑,不符合开闭原则,所以我们可以利用反射去优化代码:

public class BikeFactory {
    public Bike create(String className) {
        try {
            if (!(null == className || "".equals(className))) {
                return (Bike) Class.forName(className).newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

修改客户端代码:

public class SimpleFactoryMain extends BikeFactory {
    public static void main(String[] args) {
        BikeFactory bikeFactory = new BikeFactory();
        Bike bike = bikeFactory.create("com.factory.simplefactory.BikeFactory");
        bike.run();
    }
}

优化过后增加产品的过程中不需要优化工厂类BikeFactory的代码,但是其中的方法参数是字符串,为了提升可控性,还需要强制进行类型转换。因此需要作出如下修改:

public class BikeFactory {
    public Bike create(Class<? extends Bike> clazz) {
       try{
           if(null != clazz){
               return clazz.newInstance();
           }
       }catch (Exception e){
           e.printStackTrace();
       }
       return null;
    }
}

对客户端实现代码进行优化:

public class SimpleFactoryMain extends BikeFactory {
    public static void main(String[] args) {
        BikeFactory bikeFactory = new BikeFactory();
        Bike bike = bikeFactory.create(RoadBike.class);
        bike.run();
    }
}

下面来说下简单工厂的缺点:

  • 工厂职责过重,不易于扩展复杂的产品结构。

2.工厂方法模式

​ 工厂方法的模式(Factory Method Pattern)是指定义一个创建对象的接口,让实现这个接口的类来决定实例化哪个类,工厂方法模式就将让实例化的过程放到子类中进行。在工厂方法模式中之需关心所用到的产品所对应的工厂,无需关心所创建的细节,而且新加入的产品是符合开闭原则的。

​ 在上边的自行车工厂中,随着产品的增加,每个自行车的使用以及生产过程都会有所不同,也就是说一个工厂中的所负责的事情会变得越来越多,逐渐会变成万能工厂,比如一开始只是组装山地自行车跟公路自行车,后来又增加了越野山地车、小轮车、电动自行车等等。现在,我们要对工厂的职责进行拆分,专人专事,例如山地车只由山地工厂生产,公路车只由公路自行车生产。即对工厂本身也做一个抽象。接下来进行demo的演示

  • 例:

    先创建BikeFactory接口:

    public interface BikeFactory {
        Bike create();
    }
    

    在分别创建公路车子工厂类RoadBikeFactory:

    public class RoadBikeFactory implements BikeFactory {
        @Override
        public Bike create() {
            return new RoadBike();
        }
    }
    

    山地车子工厂类RoadBikeFactory:

    public class MountainBikeFactory implements BikeFactory {
        @Override
        public Bike create() {
            return new MountainBike();
        }
    }
    

    测试代码如下:

    public class FactoryMain {
        public static void main(String[] args) {
            BikeFactory bikeFactory = new MountainBikeFactory();
            Bike bike = bikeFactory.create();
            bike.run();
    
            bikeFactory=new RoadBikeFactory();
            bike=bikeFactory.create();
            bike.run();
        }
    }
    

    工厂方法模式使用以下场景:

    1. 创建对象需要大量重复的代码。
  • 客户端(应用类、应用层)不依赖于产品类实例如被创建、如何被实现等细节。

  • 一个类通过子类来决定创建哪个对象。

    缺点:

  • 类的个数容易增多增加复杂度。

  • 增加了系统的抽象度和理解难度。

    3.抽象工厂模式

    ​ 抽象工厂模式(Abastract Factory Pattern)是指是指提供创建一些列的相关的或者相互依赖对象的接口,无需指定他们的具体类。客户端(应用类、应用层)不依赖产品实例如何被创建、如何被实现等细节,强调的是一系列相关的产品对象(属于同一产品族),一起使用创建的对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

    ​ 这里解释下两个概念:产品等级结构跟产品族。

    佳沃山地车 佳沃头盔 佳沃车架 佳沃碳刀
    捷安特山地车 捷安特头盔 捷安特车架 捷安特碳刀
    喜德盛山地车 喜德盛头盔 喜德盛车架 喜德盛碳刀
  • 第一排的佳沃的产品代表一个产品族,有车、头盔等。每一行代表一个产品族。

  • 第一列的佳沃、捷安特等自行车,代表的是产品结构。每一列代表一层产品结构。

    现在我们用代码简单的实现下,首先创建Tyre:

    public interface Tyre {
        void turn();
    }
    

    然后创建Helmet:

    public interface Helmet {
        void wear();
    }
    

    然后创建一个工厂类BikeFactory:

    public interface BikeFactory {
        Helmet createHelmet();
        Tyre   createTyre();
    }
    

    接下来创建捷安特产品族的捷安特头盔类GiantHelmet:

    public class GiantHelmet implements Helmet {
        @Override
        public void wear() {
            System.out.println("捷安特头盔!");
        }
    }
    

    捷安特产品族的捷安特碳刀类GiantTyre:

    public class GiantTyre implements Tyre {
        @Override
        public void turn() {
            System.out.println("捷安特碳刀!");
        }
    }
    

    创建捷安特的具体工厂GiantFactory:

    public class GiantFactory extends BikeFactory {
        public Tyre crateTyre() {
            return new GiantTyre();
        }
    
        public Helmet createHelmet() {
            return new GiantHelmet();
        }
    }
    

    然后创建喜德盛头盔类XDSHelmet:

    public class XDSHelmet implements Helmet{
        @Override
        public void wear() {
            System.out.println("喜德盛头盔!");
        }
    }
    

    创建喜德盛轮胎类XDSTyre:

    public class XDSTyre implements Tyre {
        @Override
        public void turn() {
            System.out.println("喜德盛轮胎!");
        }
    }
    

    创建喜德盛的一个自行车工厂类XDSFactory:

    public class XDSFactory implements BikeFactory{
        @Override
        public Helmet createHelmet() {
            return new XDSHelmet();
        }
    
        @Override
        public Tyre createTyre() {
            return new XDSTyre();
        }
    }
    

    客户端调用代码:

    public class AbastractMain {
        public static void main(String[] args) {
            GiantFactory giantFactory = new GiantFactory();
            giantFactory.createHelmet().wear();
            giantFactory.crateTyre().turn();
        }
    }
    

    运行结果:

    
    捷安特头盔!
    捷安特碳刀!
    
    Process finished with exit code 0
    

    上边的代码完整的描述了两个产品族:捷安特品牌跟喜德盛品牌,也描述了两个产品等级:头盔跟碳刀(轮子)。抽象工厂完美描述了这一场复杂的关系。但是,我们要将车架也加入到工厂呢?那么从抽象工厂类到具体工厂都要进行调整,显然不符合开闭原则。由此得出抽象工厂的缺点。

  • 规定了所有可能被创建的产品集合,产品族中扩展新的产品比较困难,需要修改抽象工厂到,具体工厂。

  • 增加了系统的难度和可维护性。