zoukankan      html  css  js  c++  java
  • 设计模式学习-工厂模式

    1.定义

    定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。

    2.类图

    3.代码示例

     1 package com.zhaoyangwoo.factorymethod;
     2 
     3 /**
     4  * Created by john on 16/5/1.
     5  * @author wuzhaoyango
     6  * <p>
     7  *     This is a demo for factoryMethod
     8  * </p>
     9  * <p>
    10  *     工厂方法:一抽象产品类派生出多个具体产品类;一抽象工厂类派生出多个具体工厂类;每个具体工厂类只能创建一个具体产品类的实例。
    11  *     即定义一个创建对象的接口(即抽象工厂类),让其子类(具体工厂类)决定实例化哪一个类(具体产品类)。“一对一”的关系。
    12  * </p>
    13  */
    14 public class FactoryMethod {
    15 
    16     private static Factory factoryA,factoryB;
    17     private static Product productA,productB;
    18     public static void main(String[] args) {
    19         factoryA = new FactoryA();
    20         factoryB = new FactoryB();
    21         productA = factoryA.create();
    22         productB = factoryB.create();
    23         productA.getName();
    24         productB.getName();
    25     }
    26 }
    27 
    28 
    29 interface Product{
    30     void getName();
    31 }
    32 
    33 interface Factory{
    34     Product create();
    35 }
    36 
    37 class ProductA implements Product{
    38 
    39     @Override
    40     public void getName() {
    41         System.out.println("I'm productA");
    42     }
    43 }
    44 
    45 class ProductB implements Product{
    46 
    47     @Override
    48     public void getName() {
    49         System.out.println("I'm productB");
    50     }
    51 }
    52 
    53 class FactoryA implements Factory {
    54 
    55     @Override
    56     public Product create() {
    57         return new ProductA();
    58     }
    59 }
    60 
    61 class FactoryB implements Factory {
    62 
    63     @Override
    64     public Product create() {
    65         return new ProductB();
    66     }
    67 }

    4.扩展:简单工厂模式

      4.1 类图

      

      4.2 代码示例

      

     1 package com.zhaoyangwoo.simplefactory;
     2 
     3 /**
     4  * Created by john on 16/5/1.
     5  * 简单工厂实现类,ConcreteFactory是"上帝类",这个设计模式是工厂方法的一种扩展,实际使用也比较多,但是
     6  * 它并不满足开闭原则,如果拓展类一种新的产品,例如ProductC,那么必须修改create方法的判断条件,别无他法.
     7  * 这并无影响它的广泛使用,所以原则是死的,编码是活的. 
     8  */
     9 public class SimpleFactory {
    10     public static void main(String[] args){
    11         Product product = ConcreteFactory.create(ProductA.class);
    12         product.getName();
    13     }
    14 }
    15 
    16 class ConcreteFactory {
    17     public static Product create(Class t) {
    18         if(t.equals(ProductA.class)){
    19             return new ProductA();
    20         }else if(t.equals(ProductB.class)){
    21             return new ProductB();
    22         }else {
    23             throw new IllegalArgumentException("参数错误");
    24         }
    25     }
    26 }
    27 interface Product{
    28     void getName();
    29 }
    30 
    31 class ProductA implements Product {
    32 
    33     @Override
    34     public void getName() {
    35         System.out.println("I'm productA");
    36     }
    37 }
    38 
    39 class ProductB implements Product {
    40 
    41     @Override
    42     public void getName() {
    43         System.out.println("I'm productB");
    44     }
    45 }

    5.应用场景举例

    • 创建复杂对象,隔离对象创建的具体过程
    • 一个类不知道它所需要的对象的类:客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。 

    6.JDK源码中的模式实现

    还记得我们在单例模式中提到的Calendar.getInstance() 吗?它实际上就是工厂方法的一个典型实现。我们再来看看源码

     1  public static Calendar getInstance(TimeZone zone,
     2                                        Locale aLocale)
     3     {
     4         return createCalendar(zone, aLocale);
     5     }
     6 
     7     private static Calendar createCalendar(TimeZone zone,
     8                                            Locale aLocale)
     9     {
    10         CalendarProvider provider =
    11                 LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
    12                         .getCalendarProvider();
    13         if (provider != null) {
    14             try {
    15                 return provider.getInstance(zone, aLocale);
    16             } catch (IllegalArgumentException iae) {
    17                 // fall back to the default instantiation
    18             }
    19         }
    20 
    21         Calendar cal = null;
    22 
    23         //通过判断条件来决定用怎样的子类来实例化父类
    24         if (aLocale.hasExtensions()) {
    25             String caltype = aLocale.getUnicodeLocaleType("ca");
    26             if (caltype != null) {
    27                 switch (caltype) {
    28                     case "buddhist":
    29                         cal = new BuddhistCalendar(zone, aLocale);
    30                         break;
    31                     case "japanese":
    32                         cal = new JapaneseImperialCalendar(zone, aLocale);
    33                         break;
    34                     case "gregory":
    35                         cal = new GregorianCalendar(zone, aLocale);
    36                         break;
    37                 }
    38             }
    39         }
    40 
    41         //通过判断条件来决定用怎样的子类来实例化父类
    42         if (cal == null) {
    43             if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
    44                 cal = new BuddhistCalendar(zone, aLocale);
    45             } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
    46                     && aLocale.getCountry() == "JP") {
    47                 cal = new JapaneseImperialCalendar(zone, aLocale);
    48             } else {
    49                 cal = new GregorianCalendar(zone, aLocale);
    50             }
    51         }
    52         return cal;
    53     }
    View Code

    再举一个例子 NumberFormat.getInstance(),我们继续看源码

     1     public final static NumberFormat getInstance() {
     2         return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
     3     }
     4     private static NumberFormat getInstance(Locale desiredLocale,
     5                                            int choice) {
     6         LocaleProviderAdapter adapter;
     7         adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class,
     8                                                    desiredLocale);
     9         NumberFormat numberFormat = getInstance(adapter, desiredLocale, choice);
    10         if (numberFormat == null) {
    11             numberFormat = getInstance(LocaleProviderAdapter.forJRE(),
    12                                        desiredLocale, choice);
    13         }
    14         return numberFormat;
    15     }
    16 
    17 
    18     private static NumberFormat getInstance(LocaleProviderAdapter adapter,
    19                                             Locale locale, int choice) {
    20         NumberFormatProvider provider = adapter.getNumberFormatProvider();
    21         NumberFormat numberFormat = null;
    22         switch (choice) {
    23         case NUMBERSTYLE:
    24             numberFormat = provider.getNumberInstance(locale);
    25             break;
    26         case PERCENTSTYLE:
    27             numberFormat = provider.getPercentInstance(locale);
    28             break;
    29         case CURRENCYSTYLE:
    30             numberFormat = provider.getCurrencyInstance(locale);
    31             break;
    32         case INTEGERSTYLE:
    33             numberFormat = provider.getIntegerInstance(locale);
    34             break;
    35         }
    36         return numberFormat;
    37     }
    View Code 

    7.思考

    • 我们是否有必要将简单工厂/工厂方法/抽象工厂区分开来?

            我的想法是不用。要知道其实这三个设计模式的形式都是极为相似的:将实例化动作交给子类来达到解耦的目的。另外工厂方法中用静态方法+判断代替抽象类即可转化为简单工厂。如果工厂方法中的产品不止一个,即增加一个产品,产生了产品蔟的概念,那么也就轻松转化成了抽象工厂。所以我认为实际使用中,不要太在意使用了哪个工厂。

    • 产品能否是其本身?

            当然可以!单例模式其实就是工厂方法最极端的情况。

    //1.简单工厂的实现
    class ConcreteFactory {
        public static Product create(Class t) {
            if(t.equals(ProductA.class)){
                return new ProductA();
            }else if(t.equals(ProductB.class)){
                return new ProductB();
            }else {
                throw new IllegalArgumentException("参数错误");
            }
        }
    }
    //2.将工厂作为产品.看出来没,单例的雏形已经出来了
    class ConcreteFactory {
        public static ConcreteFactory create() {
           return new ConcreteFactory();
        }
    }

    8.参考

    1.设计模式(二)工厂方法模式
    2.技术之大,在乎你我心中
  • 相关阅读:
    xfce4-windowck-plugin的替代品
    git使用Beyond Compare作为diff和merge工具
    Visual Studio设置多个快捷键
    scrapy参数-COOKIES_ENABLED 最权威解释, 帮你避坑
    Linux基础使用
    python 所有的库整理
    Nginx配置详解
    15个常用的javaScript正则表达式
    Redis开发建议
    mysql 同步大量数据小技巧
  • 原文地址:https://www.cnblogs.com/zhaoyanghoo/p/5450690.html
Copyright © 2011-2022 走看看