目录
1.工厂方法
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
工厂方法即Factory Method,是一种对象创建型模式。
工厂方法的目的是使得创建对象和使用对象是分离的,并且客户端总是引用抽象工厂和抽象产品
package com.learn.factorymethod;
public interface Factory {
Number parse(String s);
}
---
package com.learn.factorymethod;
public interface NumberFactory extends Factory{
static NumberFactory impl=new NumberFactoryImpl();
//获取工厂实例
static NumberFactory getFactory(){
return impl;
}
}
---
package com.learn.factorymethod;
import java.math.BigDecimal;
public class NumberFactoryImpl implements NumberFactory{
@Override
public Number parse(String s) {
return new BigDecimal(s);
}
}
在客户端中,我们只需要和工厂接口NumberFactory
以及抽象产品Number
打交道:
NumberFactory factory=NumberFactory.getFactory();
Number result=factory.parse("123.456");
调用方可以完全忽略真正的工厂NumberFactoryImpl
和实际的产品BigDecimal
,这样做的好处是允许创建产品的代码独立地变换,而不会影响到调用方。
2.静态工厂方法
一个简单的parse()
需要写这么复杂的工厂吗?实际上大多数情况下我们并不需要抽象工厂,而是通过静态方法直接返回产品,即:
public class NumberFactory {
public static Number parse(String s) {
return new BigDecimal(s);
}
}
这种简化的使用静态方法创建产品的方式称为静态工厂方法(Static Factory Method)。静态工厂方法广泛地应用在Java标准库中。
Integer n = Integer.valueOf(66);
Integer
既是产品又是静态工厂。它提供了静态方法valueOf()
来创建Integer
。那么这种方式和直接写new Integer(100)
有何区别呢?我们观察valueOf()
方法:
public final class Integer {
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
...
}
工厂方法可以隐藏创建产品的细节,且不一定每次都会真正创建产品,完全可以返回缓存的产品,从而提升速度并减少内存消耗。
如果调用方直接使用Integer n = new Integer(100)
,那么就失去了使用缓存优化的可能性。
package com.learn.factorymethod;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
public class LocalDateFactory {
private static Map<Integer, LocalDate> cache=new HashMap<>();
public static LocalDate fromInt(int yyyyMMdd){
if(yyyyMMdd >= 20200101 && yyyyMMdd <= 20300101){
LocalDate result=cache.get(yyyyMMdd);
if(result == null){
result=create(yyyyMMdd);
cache.put(yyyyMMdd,result);
}
return result;
}
return create(yyyyMMdd);
}
public static LocalDate create(int yyyyMMdd){
return LocalDate.of(yyyyMMdd / 10000,yyyyMMdd / 100%100,yyyyMMdd % 100);
}
}
package com.learn.factorymethod;
import net.sf.cglib.core.Local;
import java.time.LocalDate;
import java.util.List;
public class Test {
public static void main(String[] args) {
NumberFactory factory=NumberFactory.getFactory();
Number result=factory.parse("123.456");
System.out.println(result);
Integer a=66;
Integer b=66;
Integer c=128;
Integer d=128;
System.out.println(a == b);
System.out.println(c == d);
LocalDate ld=LocalDateFactory.fromInt(20200202);
System.out.println(ld);
LocalDate ld2=LocalDateFactory.fromInt(20200202);
System.out.println(ld == ld2);
}
}
注:
1.总是引用接口而非实现类,能允许变换子类而不影响调用方,即尽可能面向抽象编程。
2.关于Integer.valueOf()方法
JDK在1.5版本中添加的一项新特性,把-128~127的数字缓存起来了,用于提升性能和节省内存。所以这个范围内的自动装箱(相当于调用valueOf(int i)方法)的数字都会从缓存中获取,返回同一个数字。
3.实际更常用的是更简单的静态工厂方法,它允许工厂内部对创建产品进行优化。