设计模式学习-工厂模式
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 }
再举一个例子 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 }
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.技术之大,在乎你我心中