• Java设计模式系列之工厂模式


    工厂模式将大量有共同接口的类实例化,工厂模式可以实现动态决定实例化哪一个类的对象,工厂模式在《Java与模式》中分为三类:
    1)简单工厂模式(Simple Factory):添加某一种类型的产品方便,不利于产生系列产品;
    2)工厂方法模式(Factory Method):又称为多形性工厂;
    3)抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;
                 这三种模式从上到下逐步抽象,并且更具一般性。
                 GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。

    简单工厂(Simple Factory)的定义

    简单又叫静态工厂,是工厂模式三中状态中结构最为简单的。主要有一个静态方法,用来接受参数,并根据参数来决定返回实现同一接口的不同类的实例。

    简单工厂(Simple Factory)的组成

    简单工厂模式中包含的角色及其相应的职责如下:

           工厂角色(Creator):这是简单工厂模式的核心,由它负责创建所有的类的内部逻辑。当然工厂类必须能够被外界调用,创建所需要的产品对象。

           抽象(Product)产品角色:简单工厂模式所创建的所有对象的父类,注意,这里的父类可以是接口也可以是抽象类,它负责描述所有实例所共有的公共接口。

           具体产品(Concrete Product)角色:简单工厂所创建的具体实例对象,这些具体的产品往往都拥有共同的父类。

    简单工厂(Simple Factory)的UML图

                              

    下面我们看一个具体的例子:

    一个工厂我们让它生产Car、Plane、Broom等交通工具产品,我们首先要做的就是为所有产品定义一个共同的产品接口,这个就是三个角色中的抽象产品角色(Product)。

     public interface Moveable {
         public abstract void run();
     }

    所有的交通工具都是能够移动的嘛,定义具体的产品类去实现这个接口,实现Moveable接口的类是三个角色中的具体产品角色(Concrete Product)。

    class Car implements Moveable{
    
        @Override
        public void run() {
            System.out.println("Car冒着烟开来了....");
        }
        
    }
    class Plane implements Moveable{
    
        @Override
        public void run() {
            System.out.println("扇着翅膀飞走了....");
        }
        
    }
    class Broom implements Moveable{
    
        @Override
        public void run() {
            System.out.println("骑着扫把而来....");
        }
        
    }

    接下来我们写一个工厂类,里面包含一个静态方法,根据参数决定产生哪个类的对象实例,这个工厂类是三个角色中的工厂角色(Creator)

    class Factory{
        public static Moveable factory(String productName){
            if(productName.equalsIgnoreCase("Car")){
                return new Car();
            }
            else if(productName.equalsIgnoreCase("Plane")){
                return new Plane();
            }
            else if(productName.equalsIgnoreCase("Broom")){
                return new Broom();
            }
            else
                throw new RuntimeException("你要生产的是啥呀");
            
        }
    }

    接下来我们写一个测试类:

    public class SimpleFactoryTest {
    
        public static void main(String args[]){
            Factory.factory("car").run();
            Factory.factory("plane").run();
            Factory.factory("brooM").run();
            
        }
    }

    运行结果:

    Car冒着烟开来了....
    扇着翅膀飞走了....
    骑着扫把而来....

    由上面的代码可以看出,简单工厂的核心就是一个Factory类,它拥有必要的逻辑判断能力和所有产品的创建权利,我们只需要把需求告诉工厂,就能得到我们想要的产品。这使用起来似乎非常方便。
    然而(剧情一般都会这样发展。。。)实际上,这个Factory有很多的局限。首先你看,我们每次想要增加一种新产品的时候,比如我们要产生一个交通工具叫碧眼金睛兽,都必须修改Factory的源代码。其次,当我们拥有很多很多产品的时候,而且产品之间又存在复杂的层次关系的时候,这个类必须拥有复杂的逻辑判断能力,其代码量也将不断地激增,这对以后的维护简直就是恐怖两个字...
    还有就是,整个系统都严重依赖Factory类,只要Factory类一出问题,系统就进入不能工作的状态,这也是最为致命的一点....
    以上的不足将在工厂模式的另外两种状态中得到解决。废话不多说,下面我们接着介绍:
    工厂方法(Factory Method)的定义:

     工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。

    工厂方法(Factory Method)的组成:

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

    工厂方法(Factory Method)的UML:

                

    我们首先定义抽象工厂角色,这里我们用一个抽象类来实现这个角色

     abstract class Factory {
         public abstract Moveable createProduct();
     }

    定义产生产品的具体工厂角色,去继承抽象工厂角色,也就是继承Factory类(如果不明白为啥这里用抽象类而不用接口,可以自行百度两者的区别)

    class CarFactory extends Factory{
    
        @Override
        public Moveable createProduct() {
            
            return new Car();
        }
        
    }
    class PlaneFactory extends Factory{
    
        @Override
        public Moveable createProduct() {
            
            return new Plane();
        }
        
    }
    class BroomFactory extends Factory{
    
        @Override
        public Moveable createProduct() {
            
            return new Broom();
        }
        
    }

    接下来就是我们的抽象产品角色,就是前面那个Moveable接口,代码也粘过来把,看的流畅一些

     public interface Moveable {
         public abstract void run();
     }

    最后我们来定义具体产品角色,需要实现抽象产品角色,就是前面的具体类Car、Plane、Broom嘛,我们也粘过来

    class Car implements Moveable {
    
        @Override
        public void run() {
            System.out.println("Car冒着烟开来了....");
        }
    
    }
    
    class Plane implements Moveable {
    
        @Override
        public void run() {
            System.out.println("扇着翅膀飞走了....");
        }
    
    }
    
    class Broom implements Moveable {
    
        @Override
        public void run() {
            System.out.println("骑着扫把而来....");
        }
    
    }

    接下来我们写个测试类测试一下我们的成果:

    public class SimpleFactoryTest {
    
        public static void main(String args[]) {
            // 这里用到了多态,相信大家可以看明白
            // 生产Car
            Factory factory = new CarFactory();
            Moveable m1 = factory.createProduct();
            // 生产Plane
            Factory factory2 = new PlaneFactory();
            Moveable m2 = factory2.createProduct();
            // 生产Broom
            Factory factory3 = new BroomFactory();
            Moveable m3 = factory3.createProduct();
            // 调用具体对象的方法
            m1.run();
            m2.run();
            m3.run();
        }
    }

    运行结果:

    Car冒着烟开来了....
    扇着翅膀飞走了....
    骑着扫把而来....

    从上面创建产品对象的代码可以看出,工厂方法和简单工厂的主要区别是,简单工厂是把创建产品的职能都放在一个类里面,而工厂方法则把不同的产品放在实现了工厂接口的不同工厂类里面,这样就算其中一个工厂类出了问题,其他工厂类也能正常工作,互相不受影响,以后增加新产品,也只需要新增一个实现工厂接口工厂类,就能达到,不用修改已有的代码。但工厂方法也有它局限的地方,那就是当面对的产品有复杂的等级结构的时候,例如,工厂除了生产交通工具外,还生产家电,这样一来家电、交通工具就是两大产品家族了,这两大家族下面包含了数量众多的产品,每个产品又有多个型号,这样就形成了一个复杂的产品树了。如果用工厂方法来设计这个产品家族系统,就必须为每个型号的产品创建一个对应的工厂类,当有数百种甚至上千种产品的时候,也必须要有对应的上百成千个工厂类,你没感觉工厂类有点多吗?这就出现了传说的类爆炸,工厂类泛滥了。
    没事,我们的抽象工厂可以解决这些问题,我们接着介绍:

    抽象工厂(Factory Method)

    抽象工厂:意图在于创建一系列互相关联或互相依赖的对象。
    我自己觉得抽象工厂是在工厂方法的基础上引进了分类管理的概念....
    工厂方法用来创建一个产品,它没有分类的概念,而抽象工厂则用于创建一系列产品,所以产品分类成了抽象工厂的重点

    抽象工厂的组成

     1.AbstractFactory   

      声明一个创建抽象产品对象的操作接口。

     2.ConcreteFactory

      创建具体产品对象的操作。

     3.AbstractProduct

         为一类产品对象声明一个接口。

     4.ConcreteProduct

          定义一个将被相应的具体工厂创建的产品对象。

          实现abstractProduct接口。

     5.Client

          仅使用由AbstractFactory和AbstractProduct类声明的接口

    抽象工厂(Factory Method)的UML

              

     UML图看不明白,我们直接上代码流程:

    第一步:创建AbstractFactory,里面有三个抽象函数,代表可以生产的三种抽象产品的类型  

    public abstract class abstractFactory {
    
        //生产抽象交通工具的操作接口
        public abstract vehicle createVehicle();
        //生产抽象食品的的操作接口
        public abstract Food createFood();
        //生产抽象武器的操作接口
        public abstract Weapon createWeapon();
    }

    第二步:创建ConcreteFactory,具体工厂类,去继承abstractFactory,使得具体工厂可以生产抽象工厂定义的产品系列

    默认工厂:

    //默认工厂生产的产品
    public class DefaultFactory extends abstractFactory {
    
        @Override
        public vehicle createVehicle() {
            //在我这个工厂生产的是汽车这种交通工具
            return new Car();
        }
    
        @Override
        public Food createFood() {
            //吃的是苹果
            return new apple();
        }
    
        @Override
        public Weapon createWeapon() {
            //我用的是CF中的大狙,百步穿杨
            return new Barrete();
        }
    
    }

    魔法工厂:

    //魔法工厂生产的产品系列
    public class MagicFactory  extends abstractFactory{
    
        @Override
        public vehicle createVehicle() {
            //我要生产飞机啦
            return new Plane();
        }
    
        @Override
        public Food createFood() {
            //我的食物:蘑菇
            return new MushRoom();
        }
    
        @Override
        public Weapon createWeapon() {
            //我的武器:魔法棒
            return new magicStick();
        }
    
    }

    第三步:创建抽象产品AbstractProduct,就是我们前面提到的Vehicle、Food、Weapon三个抽象产品类,附上代码

    public abstract class Weapon {
    
        public abstract void shoot();
    }
    public abstract class vehicle {
    
        public abstract void run();
    }
    public abstract class Food {
    
        public abstract void printName();
    }

    第四步:创建ConcreteProduct,就是我们的具体产品
    默认工厂生产的产品系列:Car、Apple、Barrett

    public class Car extends vehicle {
    
        @Override
        public void run() {
            System.out.println("Car...");
        }
    
    }
    public class apple extends Food {
    
        @Override
        public void printName() {
            System.out.println("apple....");
        }
    
    }
    public class Barrete extends Weapon {
    
        @Override
        public void shoot() {
            System.out.println("巴雷特狙击枪");
        }
    
    }

    魔法工厂生产的产品系列:Plane、MushRoom、magicStick

    class Plane extends vehicle {
    
        @Override
        public void run() {
            System.out.println("Plane...");
        }
    
    }
    class MushRoom extends Food {
    
        @Override
        public void printName() {
            System.out.println("MushRoom");
        }
    
    }
    class magicStick extends Weapon {
    
        @Override
        public void shoot() {
            System.out.println("魔法棒");
        }
    
    }

    第五步:创建Client,就是我们的测试类Test,来测试一下我们的工厂

    我们使用默认工厂生产产品系列

    public class ClientTest {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
    
            abstractFactory factory =new DefaultFactory();
            Vehicle vehicle=factory.createVehicle();
            vehicle.run();
            Food food=factory.createFood();
            food.printName();
            Weapon weapon=factory.createWeapon();
            weapon.shoot();
            System.out.println("--------分割线---------");
        }
    
    } 

    运行结果:

    Car...
    apple....
    巴雷特狙击枪
    --------分割线---------

    当我们想使用魔法工厂生产另一个产品系列时只需要更改很少的代码

    public class ClientTest {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
    
            //注意就改了这一个位置,把defaultFactory换成MagicFactory即可
            abstractFactory factory =new MagicFactory();
            Vehicle vehicle=factory.createVehicle();
            vehicle.run();
            Food food=factory.createFood();
            food.printName();
            Weapon weapon=factory.createWeapon();
            weapon.shoot();
            System.out.println("--------分割线---------");
        }
    
    }

    运行结果:

    Plane...
    MushRoom
    魔法棒
    --------分割线---------
    在抽象工厂模式中,抽象产品 (AbstractProduct) 可能是一个或多个,从而构成一个或多个产品族(Product Family)。 在只有一个产品族的情况下,抽象工厂模式实际上退化到工厂方法模式。

    总结:

    (1)简单工厂模式是由一个具体的类去创建其他类的实例,父类是相同的,父类是具体的。
    (2)工厂方法模式是有一个抽象的父类定义公共接口,子类负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成。
    (3)抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。它针对的是有多个产品的等级结构。而工厂方法模式针对的是一个产品的等级结构。


    本文为博主原创文章,转载请注明出处:http://www.cnblogs.com/ysw-go/
    1、本博客的原创原创文章,都是本人平时学习所做的笔记,如有错误,欢迎指正。
    2、如有侵犯您的知识产权和版权问题,请通知本人,本人会即时做出处理文章。
    3、本博客的目的是知识交流所用,转载自其它博客或网站,作为自己的参考资料的,感谢这些文章的原创人员

  • 相关阅读:
    List for game to play latter
    C语言基础问题总结
    Java基础学习总结(70)——开发Java项目常用的工具汇总
    谈谈普通码农如何不靠工资也能月入过万
    Java基础学习总结(69)——匿名内部类与Lambda表达式
    Html学习总结(2)——Html页面head标签元素的意义和应用场景
    Android学习总结(5)——9个非常有用的Andorid 程序片段
    Mysql学习总结(39)——30条MySql语句优化技巧
    Java基础学习总结(68)——有关Java线程方面的面试题
    Mysql学习总结(38)——21条MySql性能优化经验
  • 原文地址:https://www.cnblogs.com/ysw-go/p/5394179.html
Copyright © 2020-2023  润新知