设计模式学习-工厂模式

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.技术之大,在乎你我心中
posted @ 2016-05-01 17:31  jiudianban  阅读(453)  评论(0编辑  收藏  举报