美文网首页
3、工厂模式(Factory Pattern)

3、工厂模式(Factory Pattern)

作者: 火山_6c7b | 来源:发表于2020-07-26 22:53 被阅读0次

    1. 简介

      工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。所以工厂模式可以分为三类:

    • 简单工厂模式(Simple Factory)
    • 工厂方法模式(Factory Method)
    • 抽象工厂模式(Abstract Factory)

      这三种模式从上到下逐步抽象,并且更具一般性。简单工厂、工厂方法、抽象工厂都属于设计模式中的创建型模式。其主要功能都是帮助我们把对象的实例化部分抽象取了出来,优化了系统的架构,并且增强了系统的扩展性。此篇博客是笔者对学完这三种模式之后一个小小的总结。

    1.1 简单工厂

      简单工厂模式的工厂类一般是使用静态方法,通过接收的参数不同来返回不同的对象实例。不修改代码的话,是无法扩展的

    • 优点:客户端可以免除直接创建产品对象的责任,而仅仅是“消费”产品。简单工厂模式通过这种做法实现了对责任的分割
    • 缺点:由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了

    1.2 工厂方法

      工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。在同一等级结构中,支持增加任意产品

    • 优点:允许系统在不修改具体工厂角色的情况下引进新产品
    • 缺点:由于每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量

    1.3 抽象工厂

      抽象工厂是应对产品族概念的。应对产品族概念而生,增加新的产品线很容易,但是无法增加新的产品。比如,每个汽车公司可能要同时生产轿车、货车、客车,那么每一个工厂都要有创建轿车、货车和客车的方法

    • 优点:向客户端提供一个接口,使得客户端在不必指定产品具体类型的情况下,创建多个产品族中的产品对象
    • 缺点:增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性

    2. 实现

    2.1 简单工厂模式

      该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象,其UML类图如下:


    简单工厂模式uml.png

    Phone类:

    public interface Phone {
        void make();
    }
    

    MiPhone类:

    public class MiPhone implements Phone {
        public MiPhone() {
            this.make();
        }
        @Override
        public void make() {
            // TODO Auto-generated method stub
            System.out.println("make xiaomi phone!");
        }
    }
    

    IPhone类:

    public class IPhone implements Phone {
        public IPhone() {
            this.make();
        }
        @Override
        public void make() {
            // TODO Auto-generated method stub
            System.out.println("make iphone!");
        }
    }
    

    PhoneFactory类:

    public class PhoneFactory {
        public Phone makePhone(String phoneType) {
            if(phoneType.equalsIgnoreCase("MiPhone")){
                return new MiPhone();
            }
            else if(phoneType.equalsIgnoreCase("iPhone")) {
                return new IPhone();
            }
            return null;
        }
    }
    

    客户端调用:

    public class Demo {
        public static void main(String[] arg) {
            PhoneFactory factory = new PhoneFactory();
            Phone miPhone = factory.makePhone("MiPhone");            // make xiaomi phone!
            IPhone iPhone = (IPhone)factory.makePhone("iPhone");    // make iphone!
        }
    }
    

    2.2 工厂方法模式(Factory Method)

      和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂,其UML类图如下:


    工厂方法模式uml.png

    AbstractFactory类:

    public interface AbstractFactory {
        Phone makePhone();
    }
    

    XiaoMiFactory类:

    public class XiaoMiFactory implements AbstractFactory{
        @Override
        public Phone makePhone() {
            return new MiPhone();
        }
    }
    

    AppleFactory类:

    public class AppleFactory implements AbstractFactory {
        @Override
        public Phone makePhone() {
            return new IPhone();
        }
    }
    

    客户端调用示例:

    public class Demo {
        public static void main(String[] arg) {
            AbstractFactory miFactory = new XiaoMiFactory();
            AbstractFactory appleFactory = new AppleFactory();
            miFactory.makePhone();            // make xiaomi phone!
            appleFactory.makePhone();        // make iphone!
        }
    }
    

    2.3 反射

      简单工厂模式与工厂方法模式真正的避免了代码的改动了?没有。在简单工厂模式中,新产品的加入要修改工厂角色中的判断语句;而在工厂方法模式中,要么将判 断逻辑留在抽象工厂角色中,要么在客户程序中将具体工厂角色写死(就象上面的例子一样)。而且产品对象创建条件的改变必然会引起工厂角色的修改。

      面对这种情况,我们可以使用反射机制:

    public class PhoneFactory {
        public Phone makePhone( String className) {
            Class clazz = Class.forName(className);
            factory = (PhoneFactory) Class.forName(className).newInstance();
            return factory.makePhone();
        }
    }
    

    2.4 抽象工厂模式(Abstract Factory)

      上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品Phone(AbstractProduct),如果要生成另一种产品PC,应该怎么表示呢?

      最简单的方式是把2中介绍的工厂方法模式完全复制一份,不过这次生产的是PC。但同时也就意味着我们要完全复制和修改Phone生产管理的所有代码,显然这是一个笨办法,并不利于扩展和维护。

      抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。其UML类图如下:


    抽象工厂模式uml.png

    PC类:

    public interface PC {
        void make();
    }
    

    MiPC类:

    public class MiPC implements PC {
        public MiPC() {
            this.make();
        }
        @Override
        public void make() {
            // TODO Auto-generated method stub
            System.out.println("make xiaomi PC!");
        }
    }
    

    MAC类:

    public class MAC implements PC {
        public MAC() {
            this.make();
        }
        @Override
        public void make() {
            // TODO Auto-generated method stub
            System.out.println("make MAC!");
        }
    }
    

    AbstractFactory类:

    public interface AbstractFactory {
        Phone makePhone();
        PC makePC();
    }
    

    XiaoMiFactory类:

    public class XiaoMiFactory implements AbstractFactory{
        @Override
        public Phone makePhone() {
            return new MiPhone();
        }
        @Override
        public PC makePC() {
            return new MiPC();
        }
    }
    

    AppleFactory类:

    public class AppleFactory implements AbstractFactory {
        @Override
        public Phone makePhone() {
            return new IPhone();
        }
        @Override
        public PC makePC() {
            return new MAC();
        }
    }
    

    客户端调用示例:

    public class Demo {
       public static void main(String[] arg) {
           AbstractFactory miFactory = new XiaoMiFactory();
           AbstractFactory appleFactory = new AppleFactory();
           miFactory.makePhone();            // make xiaomi phone!
           miFactory.makePC();                // make xiaomi PC!
           appleFactory.makePhone();        // make iphone!
           appleFactory.makePC();            // make MAC!
       }
    }
    

    相关文章

      网友评论

          本文标题:3、工厂模式(Factory Pattern)

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