• OO之工厂模式


    以下为工厂模式的详解,包括简单工厂,普通工厂模式,抽象工厂。

    引子:

           假设有一个交通工具公司,生产自行车,汽车,飞机等,现要销售该公司的产品,要怎么设计呢?

           在交通工具商店中加一个if else判断如果是自行车就实例化(new)一个自行车,如果是汽车就实例化(new)一个汽车吗,当然不是,这样的话如果将来又加了多种交通工具那要更改每一个商店的代码,这样的话更改太多,我们应该把这部分可能变更的代码封装到另一个对象中,这个对象只管生产何种交通工具,要获得交通工具就用它。

    简单工厂:

    类图:

    设计:

    /**
     * 抽像的交通工具类,里面有生产交通工具的过程方法(控制生产过程)
     * @author Homg
     *
     */
    public abstract class Vehicle {
            public abstract void produceComponent();
            public abstract void assemble();
            public abstract void test();
    }

    具体产品类,其他具体产品类(bike,plane)省略,完整代码在文章的最下方有下载地址:

    /**
     * 具体的产品,继承自抽象类,以用被工厂生产出来
     * @author Homg
     *
     */
    public class Car extends Vehicle{
    
        @Override
        public void produceComponent() {
            // TODO Auto-generated method stub
            System.out.println("生产汽车零件");
        }
    
        @Override
        public void assemble() {
            // TODO Auto-generated method stub
            System.out.println("组装成汽车");
        }
    
        @Override
        public void test() {
            // TODO Auto-generated method stub
            System.out.println("测试汽车性能");
        }
    
    }
    /**
     * 简单交通工具工厂,这是唯一new具体交通工具的地方
     * 
     * @author Homg
     * 
     */
    public class SimpleVehicleFactory {
        // 该方法也可以是静态的(静态工厂)
        public Vehicle createVehicle(String type) {
            Vehicle vehicle = null;
            if ("bike".equals(type)) {
                vehicle = new Bike();
            } else if ("car".equals(type)) {
                vehicle = new Car();
            } else if ("plane".equals(type)) {
                vehicle = new Plane();
            }
            //可以设置默认产品以免为null
            return vehicle;
        }
    }
    /**
     * 销售交通工具,工厂的使用者。
     * 
     * @author Homg
     * 
     */
    public class VehicleStore {
        // 工厂的引用,从构造函数中获得
        private SimpleVehicleFactory factory;
    
        public VehicleStore(SimpleVehicleFactory factory) {
            this.factory = factory;
        }
    
        // 通过传入订单的类型来获得相应的产品,不需要实例化(new)任何一个具体类,全部通过createVehicle()来获得。
        public Vehicle orderVehicle(String type) {
            Vehicle vehicle;
            vehicle = factory.createVehicle(type);
            vehicle.produceComponent();
            vehicle.assemble();
            vehicle.test();
            return vehicle;
        }
    }

    测试:

        public static void main(String[] args) {
            SimpleVehicleFactory factory = new SimpleVehicleFactory();
            VehicleStore vehicleStore = new VehicleStore(factory);
            // 依次生产三种交通工具
            Vehicle vehicle1 = vehicleStore.orderVehicle("car");
            System.out.println("-------------------------------------");
            Vehicle vehicle2 = vehicleStore.orderVehicle("bike");
            System.out.println("-------------------------------------");
            Vehicle vehicle3 = vehicleStore.orderVehicle("plane");
        }

    运行结果:
    生产汽车零件
    组装成汽车
    测试汽车性能
    -------------------------------------
    生产自行车零件
    组装成自行车
    测试自行车性能
    -------------------------------------
    生产飞机零件
    组装成飞机
    测试飞机性能

    ˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙

          以后如果有新的交通工具要生产,只需要更改工厂类一处即可,商店类中不需要实例化任何一个具体的交通工具类,实例化(new)操作都放到工厂类的方法中。工厂类中的创建方法也可以改成静态的(静态工厂),这样可以不用实例化对象来使用工厂方法。

         简单工厂严格来说并不是真正的工厂模式,下来我们来看普通工厂模式

         现在该公司不仅要在中国销售产品,还要把产品销售到俄罗斯,也就是说,不仅要分多种产品类型,还要分不同区域生产不同风格的产品。

    先看一下工厂模式的基本类图:

    设计(省略部分类似代码,完整代码在文章的最下方有下载地址。):

         首先要进行一些质量控制,确保分公司产品是用的总公司的流程,但不同地区的产品又需要有自己的变化,所以产品类应该这样:

    /**
     * 产品类,抽像的交通工具类,里面有生产交通工具的过程方法(控制生产过程),但抽象的由子具体实现
     * 
     * @author Homg
     * 
     */
    public abstract class Vehicle {
        String name;
        //各种零件
        String tyre;
        String engine;
        String body;
    
        public void produceComponent() {
            System.out.println("名字:" + name);
            System.out.println("轮胎:" + tyre);
            System.out.println("引擎:" + engine);
            System.out.println("机身:" + body);
        }
    
        public abstract void assemble();
    
        public abstract void test();
    }

    子类决定具体的产品(其他具体产品类省略):

    /**
     * 具体的产品,继承自抽象类,根据不同地域有不同的产品
     * @author Homg
     *
     */
    public class ChineseCar extends Vehicle{
        
        public ChineseCar() {
            name="中国汽车";
            tyre="中国汽车轮胎";
            engine="中国汽车引擎";
            body="中国风格汽车机身";
        }
    
        @Override
        public void assemble() {
            // TODO Auto-generated method stub
            System.out.println("组装成中国风格汽车");
        }
    
        @Override
        public void test() {
            // TODO Auto-generated method stub
            System.out.println("测试俄中国格汽车性能");
        }
    
    }
    /**
     * 具体的产品,继承自抽象类,根据不同地域有不同的产品
     * @author Homg
     *
     */
    public class RussiaCar extends Vehicle{
        
        public RussiaCar() {
            name="俄罗斯汽车";
            tyre="俄罗斯汽车轮胎";
            engine="俄罗斯汽车引擎";
            body="俄罗斯风格汽车机身";
        }
    
        @Override
        public void assemble() {
            // TODO Auto-generated method stub
            System.out.println("组装成俄罗斯风格汽车");
        }
    
        @Override
        public void test() {
            // TODO Auto-generated method stub
            System.out.println("测试俄罗斯风格汽车性能");
        }
    
    }

    工厂类需要制定一个框架,既要生产产品,不同区域又可以生产不同的产品(抽象的工厂方法):

    /**
     * 创建者类,定义了一个抽象的工厂方法,由子类具体实现创建什么新产品
     * @author Homg
     *
     */
    public abstract class VehicleFactory {
        //生产产品,不用管具体生产什么产品,由createVehicle方法来管
        public Vehicle orderVehicle(String type) {
            Vehicle vehicle;
            vehicle = createVehicle(type);
            vehicle.produceComponent();
            vehicle.assemble();
            vehicle.test();
            return vehicle;
        }
        //抽象的创建产品方法,返回具体的产品,参数决定是什么产品。
        protected abstract Vehicle createVehicle(String type);
        //其他方法
    }

    子类工厂重写工厂方法,决定生产什么地区的产品:

    /**
     * 具体的工厂类,根据不同地域创建不同的产品
     * 
     * @author Homg
     * 
     */
    public class ChineseVehicleFactory extends VehicleFactory {
        // 创建不同的产品
        @Override
        protected Vehicle createVehicle(String type) {
            // TODO Auto-generated method stub
            Vehicle vehicle = null;
            if ("bike".equals(type)) {
                vehicle = new ChineseBike();
            } else if ("car".equals(type)) {
                vehicle = new ChineseCar();
            }
            // 可以设置默认产品以免为null
            return vehicle;
        }
    
    }
    /**
     * 具体的工厂类,根据不同地域创建不同的产品
     * 
     * @author Homg
     * 
     */
    public class RussiaVehicleFactory extends VehicleFactory {
        // 创建不同的产品
        @Override
        protected Vehicle createVehicle(String type) {
            // TODO Auto-generated method stub
            Vehicle vehicle = null;
            if ("bike".equals(type)) {
                vehicle = new RussiaBike();
            } else if ("car".equals(type)) {
                vehicle = new RussiaCar();
            }
            // 可以设置默认产品以免为null
            return vehicle;
        }
    
    }

    测试:

        public static void main(String[] args) {
            VehicleFactory chinesefactory=new ChineseVehicleFactory();
            Vehicle chineseVehicle1=chinesefactory.orderVehicle("bike");
            System.out.println("--------------------------------------");
            Vehicle chineseVehicle2=chinesefactory.orderVehicle("car");
            System.out.println("--------------------------------------");
            VehicleFactory russiaFactory=new RussiaVehicleFactory();
            russiaFactory.orderVehicle("bike");
            System.out.println("--------------------------------------");
            russiaFactory.orderVehicle("car");
        }

    运行结果:

    名字:中国自行车
    轮胎:中国自行车轮胎
    引擎:生物动力
    机身:中国风格自行车机身
    组装成中国风格自行车
    测试中国风格自行车性能
    --------------------------------------
    名字:中国汽车
    轮胎:中国汽车轮胎
    引擎:中国汽车引擎
    机身:中国风格汽车机身
    组装成中国风格汽车
    测试俄中国格汽车性能
    --------------------------------------
    名字:俄罗斯自行车
    轮胎:俄罗斯自行车轮胎
    引擎:生物动力
    机身:俄罗斯风格自行车机身
    组装成俄罗斯风格自行车
    测试俄罗斯风格自行车性能
    --------------------------------------
    名字:俄罗斯汽车
    轮胎:俄罗斯汽车轮胎
    引擎:俄罗斯汽车引擎
    机身:俄罗斯风格汽车机身
    组装成俄罗斯风格汽车
    测试俄罗斯风格汽车性能

    类图(产品和工厂是平行的类层级):

    理解:

      工厂方法可以封装实例化的行为,封装以后可能经常变化的代码,避免代码的重复,方便以后维护。

    ˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙˙☆`·.·˙˙`·..·˙˙`·..·˙☆`·.·˙˙`·..·˙☆˙

          现在来谈谈零件的生产,每次该公司要生产一批零件,用以制造某个产品,这时可以看看抽象工厂

    基本类图如下:

    设计:

    抽象工厂类:

    /**
     * 抽象工厂接口,定义了一组接口用来创建产品
     * @author Homg
     *
     */
    public interface ComponentFactory {
            public Tyre createTyre();
            public Engine createEngine();
            public Body createBody();
    }

    具体工厂类,不同地区的零件有不同的具体工厂:

    /**
     * 具体工厂,实现了产品家族,用户想要什么产品就用什么工厂,不需要实例化任何产品
     * @author Homg
     *
     */
    public class ChineseComponentFactory implements ComponentFactory {
    
        @Override
        public Tyre createTyre() {
            // TODO Auto-generated method stub
            return new ChineseTyre();
        }
    
        @Override
        public Engine createEngine() {
            // TODO Auto-generated method stub
            return new ChineseEngine();
        }
    
        @Override
        public Body createBody() {
            // TODO Auto-generated method stub
            return new ChineseBody();
        }
    
    }
    /**
     * 具体工厂,实现了产品家族,用户想要什么产品就用什么工厂,不需要实例化任何产品
     * @author Homg
     *
     */
    public class RussiaComponentFactory implements ComponentFactory {
    
        @Override
        public Tyre createTyre() {
            // TODO Auto-generated method stub
            return new RussiaTyre();
        }
    
        @Override
        public Engine createEngine() {
            // TODO Auto-generated method stub
            return new RussiaEngine();
        }
    
        @Override
        public Body createBody() {
            // TODO Auto-generated method stub
            return new RussiaBody();
        }
    
    }

    零件家族(省略其他零件类:engine,body。完整代码在文章的最下方有下载地址):

    /**
     * 抽象产品
     * @author Homg
     *
     */
    public abstract class Tyre {
        String name;
    
        public String getName() {
            return name;
        }
        
    }
    /**
     * 具体产品
     * @author Homg
     *
     */
    public class RussiaTyre extends Tyre {
    
        public RussiaTyre() {
            name="俄罗斯轮胎";
        }
    
    }
    /**
     * 具体产品
     * @author Homg
     *
     */
    public class ChineseTyre extends Tyre {
    
        public ChineseTyre() {
            name = "中国轮胎";
        }
    
    }

    客户类:

    /**
     * 客户类
     * @author Homg
     *
     */
    public class Client {
        private Tyre tyre;
        private Engine engine;
        private Body body;
        private ComponentFactory componentFactory;
    
        public Client(String zoom) {
            if ("俄罗斯".equals(zoom)) {
                componentFactory = new RussiaComponentFactory();
                tyre = componentFactory.createTyre();
                engine = componentFactory.createEngine();
                body = componentFactory.createBody();
                System.out.println("生产的一批零件为:" + tyre.getName() + ","
                        + engine.getName() + "," + body.getName());
            } else if ("中国".equals(zoom)) {
                componentFactory = new ChineseComponentFactory();
                tyre = componentFactory.createTyre();
                engine = componentFactory.createEngine();
                body = componentFactory.createBody();
                System.out.println("生产的一批零件为:" + tyre.getName() + ","
                        + engine.getName() + "," + body.getName());
            }
        }
    }

     测试:

        public static void main(String[] args) {
            Client client1=new Client("俄罗斯");
            System.out.println("------------------------------");
            Client client2=new Client("中国");
        }

    运行结果:
    生产的一批零件为:俄罗斯轮胎,俄罗斯引擎,俄罗斯机身
    ------------------------------
    生产的一批零件为:中国轮胎,中国引擎,中国机身

    理解:

      由上面可以看出,抽象工厂是用来创建一组产品的,也就是产品家族,用户不需要关心实际生产的具体产品是什么,只需要使用相应的工厂,这样可以将用户从具体产品中解耦。

          而普通工厂可以理解为是用来生产一个产品,抽象工厂用来生产产品家族。

    总结:

      普通工厂模式:定义了一个创建产品对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

      抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

    完整代码下载地址(也可以留下邮箱发给你):

     http://download.csdn.net/detail/homg92/6919563

  • 相关阅读:
    回溯法之图的着色问题
    回溯法基本思想
    L2-006 树的遍历
    P1540 机器翻译
    P1067 多项式输出
    C++STL之map映照容器
    C++STL之multiset多重集合容器
    C++STL之set集合容器
    C++之string基本字符系列容器
    C++STL之vector向量容器
  • 原文地址:https://www.cnblogs.com/homg/p/3548110.html
Copyright © 2020-2023  润新知