zoukankan      html  css  js  c++  java
  • 002-创建型-00-简单工厂【非23种GOF设计模式】

    一、概述

      简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。

      简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,简单来说就是,通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

      有一个工厂对象决定创建出哪一种产品类的实例

    1.1、使用场景

      工厂类负责创建的对象比较少

      客户端(应用层)只知道传入工厂类的参数对于如何创建对象(逻辑)不关心

      由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。

    1.2、优缺点

    优点:简单工厂模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在创建时可以直接使用工厂类去创建所需的实例,而无需去了解这些对象是如何创建以及如何组织的,明确区分了各自的职责和权力,有利于整个软件体系结构的优化。

    缺点:很明显简单工厂模式的缺点也体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则,另外,当系统中的具体产品类不断增多时,可能会出现要求更改相应工厂类的情况,拓展性并不是很好。

    1.3、类图角色以及职责

       1、工厂(Creater)角色

        简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。(FruitFactory类)

       2、抽象(Product)角色

        简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。(Fruit接口)

       3、具体产品(Concrete Product)角色

        简单工厂模式所创建的具体实例对象。(Apple类与Banana类)

    1.4、演进

    版本一、基础使用

    public class Apple {
        public void get() {
            System.out.println("采集苹果");
        }
    }
    public class Banana {
        public void get() {
            System.out.println("采集香蕉");
        }
    }

    用户使用

        @Test
        public void base001() {
            //实例化Apple
            Apple apple = new Apple();
            //实例化Banana
            Banana banana = new Banana();
    
            apple.get();
            banana.get();
        }

    版本二、相似功能的抽取,抽象化【接口化】

    public interface Fruit {
        void get();
    }

    上述两个类实现

    public class Apple implements Fruit {
        public void get() {
            System.out.println("采集苹果");
        }
    }
    public class Banana implements Fruit{
        public void get() {
            System.out.println("采集香蕉");
        }
    }

    测试使用

        @Test
        public void base002() {
            //实例化Apple,用到了多态
            Fruit apple = new Apple();
            //实例化Banana,用到了多态
            Fruit banana = new Banana();
    
            apple.get();
            banana.get();
        }

    版本三、简单工厂模式的基本使用

      简单工厂模式则是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类,上面的代码可以看出Apple与Banana实现了同一个接口,所以我们还需要创建一个工厂类来专门创建Apple与Banana的实例,继续改进 

    在版本二的接口基础上增加一个工厂类

    public class FruitFactory001 {
        //获取Apple的实例,用static修饰,方便使用
        public static Fruit getApple() {
            return new Apple();
        }
    
        //获取Banana的实例,用static修饰,方便使用
        public static Fruit getBanana() {
            return new Banana();
        }
    }

    测试

        @Test
        public void base003() {
            //实例化Apple,用到了工厂类
            Fruit apple = FruitFactory001.getApple();
            //实例化Banana,用到了工厂类
            Fruit banana = FruitFactory001.getBanana();
    
            apple.get();
            banana.get();
        }

    版本四、简单工厂模式的基本使用【工厂优化一】

      上述的工厂类还不够好,例子中只有两个实例对象,但如果例子多了以后,工厂类就会产生很多很多的get方法。所以进行如下优化

    public class FruitFactory002 {
        public static Fruit getFruit(String type) throws InstantiationException, IllegalAccessException {
            //不区分大小写
            if (type.equalsIgnoreCase("Apple")) {
                return Apple.class.newInstance();
            } else if (type.equalsIgnoreCase("Banana")) {
                return Banana.class.newInstance();
            } else {
                System.out.println("找不到相应的实体类");
                return null;
            }
        }
    }

    测试

        @Test
        public void base004() throws Exception {
            //实例化Apple,用到了工厂类
            Fruit apple = FruitFactory002.getFruit("apple");
            //实例化Banana,用到了工厂类
            Fruit banana = FruitFactory002.getFruit("banana");
    
            apple.get();
            banana.get();
        } 

    版本五、简单工厂模式的基本使用【工厂优化二】

      上述可以根据传入的参数动态的创建实例对象,而且传入的参数还可以自定义,非常的灵活,但缺点也很明显,工厂类中有大量的判断。

    public class FruitFactory003 {
        public static Fruit getFruit(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
            Class fruit = Class.forName(type);
            return (Fruit) fruit.newInstance();
        }
    }

    测试

        @Test
        public void base005() throws Exception {
            //实例化Apple,用到了工厂类
            Fruit apple = FruitFactory003.getFruit("com.github.bjlhx15.patterns.base.create.samplefactory.Apple");
            //实例化Banana,用到了工厂类
            Fruit banana = FruitFactory003.getFruit("com.github.bjlhx15.patterns.base.create.samplefactory.Banana");
    
            apple.get();
            banana.get();
        }

    这种方法可以看到,工厂类非常的简洁,但主方法在调用时,输入的参数就固定了,必须为实例类名,不像上一种方法那么灵活。

    二、扩展

    2.1、JDK1.8 Calendar类中的简单工厂

    Calendar.java类,Ctrl+F12查看方法列表中的getInstance()方法,中的createCalendar 使用了简单工厂模式创建对象

        private static Calendar createCalendar(TimeZone zone,
                                               Locale aLocale)
        {
            CalendarProvider provider =
                LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                                     .getCalendarProvider();
            if (provider != null) {
                try {
                    return provider.getInstance(zone, aLocale);
                } catch (IllegalArgumentException iae) {
                    // fall back to the default instantiation
                }
            }
    
            Calendar cal = null;
    
            if (aLocale.hasExtensions()) {
                String caltype = aLocale.getUnicodeLocaleType("ca");
                if (caltype != null) {
                    switch (caltype) {
                    case "buddhist":
                    cal = new BuddhistCalendar(zone, aLocale);
                        break;
                    case "japanese":
                        cal = new JapaneseImperialCalendar(zone, aLocale);
                        break;
                    case "gregory":
                        cal = new GregorianCalendar(zone, aLocale);
                        break;
                    }
                }
            }
            if (cal == null) {
                // If no known calendar type is explicitly specified,
                // perform the traditional way to create a Calendar:
                // create a BuddhistCalendar for th_TH locale,
                // a JapaneseImperialCalendar for ja_JP_JP locale, or
                // a GregorianCalendar for any other locales.
                // NOTE: The language, country and variant strings are interned.
                if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                    cal = new BuddhistCalendar(zone, aLocale);
                } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                           && aLocale.getCountry() == "JP") {
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                } else {
                    cal = new GregorianCalendar(zone, aLocale);
                }
            }
            return cal;
        }

    查看UML类图,选中Calendar,Ctrl+Alt+Shfit+U,选中Java class diagrams生成Calendar类相关的类图;Ctrl+Alt+B可以显示该类的实现类。

      

  • 相关阅读:
    如何:为 Silverlight 客户端生成双工服务
    Microsoft Sync Framework 2.1 软件开发包 (SDK)
    Windows 下的安装phpMoAdmin
    asp.net安全检测工具 Padding Oracle 检测
    HTTP Basic Authentication for RESTFul Service
    Windows系统性能分析
    Windows Server AppFabric Management Pack for Operations Manager 2007
    Mongo Database 性能优化
    服务器未能识别 HTTP 标头 SOAPAction 的值
    TCP WAIT状态及其对繁忙的服务器的影响
  • 原文地址:https://www.cnblogs.com/bjlhx/p/11133089.html
Copyright © 2011-2022 走看看