简单工厂&工厂方法
一直以来总是分不清简单工厂,工厂方法,抽象工厂这三个设计模式的区别,倒不是不理解其区别,而是总是记忆混淆,傻傻分不清楚,所以再重新总结一下区别,并记录下来,下次再混淆时,可以拿出来看看。这节先说简单工厂和工厂方法,下一节再说抽象工厂。
工厂方法中其实就包含了简单工厂,简单工厂也称为静态工厂方法,
简单工厂模式(Simple Factory)
类图
简单工厂模式又称为静态工厂方法模式,是工厂方法模式的一种,简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。注意这里工厂类传入的参数,是工厂类新建产品的依据,可以是一个字符串,也可以是自己定义的Enum或者Int值。
以一个汽车工厂为例,可以生产3种不同类型的汽车,SUV,Sedan,MPV,每个汽车都有drive方法。如果不使用简单工厂而是直接创建的话,如下面的例子。
public class User {
public static SUV suv;
public static void main(String[] args) {
suv=new SUV();
suv.drive();
}
}
class SUV{
public void drive(){
System.out.println("SUV is driving");
}
}
class Sedan{
public void drive(){
System.out.println("Sedan is driving");
}
}
class MPV{
public void drive(){
System.out.println("MPV is driving");
}
}
乍看起来没问题,想要什么产品,那就直接新建一个就好了,不过问题在于,对于使用产品的类,只能持有对应产品的对象,例如上面的例子,我持有SUV的对象,然后新建SUV的对象,当有一天有了新的产品了,并且需要替换SUV。还需要修改使用的主体。这就使使用产品的主体和产品紧紧耦合在了一起。不利于代码的复用和拓展。
把上面的代码稍微修改一下,将所有车辆抽象为一个Vehicle接口,让User持有一个Vehicle对象,新建一个工厂类,根据传入的参数不同,返回不同的对象给User使用。并且工厂类创建产品的函数是静态的,这样就不需要先创建一个工厂类了。
代码:
interface Vehicle{
public void drive();
}
class SUV implements Vehicle {
@Override
public void drive(){
System.out.println("SUV is driving");
}
}
class Sedan implements Vehicle{
@Override
public void drive() {
System.out.println("Sedan is driving");
}
}
class MPV implements Vehicle{
@Override
public void drive(){
System.out.println("MPV is driving");
}
}
enum VehcleType{
suv,sedan,mpv
}
public class SimpleFactory {
public static Vehicle makeVehicle(VehcleType type){
switch(type){
case suv:
return new SUV();
case sedan:
return new Sedan();
case mpv:
return new MPV();
default:
break;
}
return null;
}
}
测试代码:
public class User {
public static Vehicle mVehicle;
public static void main(String[] args) {
mVehicle=SimpleFactory.makeVehicle(VehcleType.suv);
mVehicle.drive();
}
}
这样就好多了。不过有些情况还是不够好,比如:
当我需要生产一种新的车型,比如敞篷车 Convertible. 但是我在SimpleFactory.makeVehicle时,并没有这种车型,那就需要修改SimpleFactory类让它增加一个case判断,并新建一个Convertible对象。但是我们并不希望SimpleFactory这个工厂类开放给用户,也就造成了没办法去增加车型。 如何才能让User任意的增加车型呢? 这就扩展出了工厂方法模式
工厂方法模式(Factory Method)
继续上面的说,User可以只知道一个Vehicle接口对象和一个Factory接口对象,对于SUV来说它实现了Vehicle接口,同时也需要SUVFactory来实现Factory接口并创建它,这样对User来说,只需要创建一个SUVFactory对象,然后通过SUVFactory类创建一个SUV对象。 如果客户自己想增加一个Convertible产品。那只需要实现自己的Convertible类和ConvertibleFactory类。然后用同样的方式生产即可。
类图
代码:
车辆相关
public interface Vehicle {
public void drive();
}
class SUV implements Vehicle {
@Override
public void drive(){
System.out.println("SUV is driving");
}
}
class Sedan implements Vehicle{
@Override
public void drive() {
System.out.println("Sedan is driving");
}
}
class MPV implements Vehicle{
@Override
public void drive(){
System.out.println("MPV is driving");
}
}
工厂相关
public interface Factory {
public Vehicle makeVehicle();
}
class SUVFactory implements Factory{
@Override
public Vehicle makeVehicle() {
return new SUV();
}
}
class SedanFactory implements Factory{
@Override
public Vehicle makeVehicle() {
return new Sedan();
}
}
class MPVFactory implements Factory{
@Override
public Vehicle makeVehicle() {
return new MPV();
}
}
客户类:
public class User {
public static Vehicle mVehicle;
public static Factory mFactory;
public static void main(String[] args) {
mFactory=new SUVFactory();
mVehicle=mFactory.makeVehicle();
mVehicle.drive();
}
}
这时,我们想要改生产Convertible车辆,只需要增加Convertible和对应工厂,并修改客户类的实现即可:
class Convertible implements Vehicle{
@Override
public void drive(){
System.out.println("Convertible is driving");
}
}
class ConvertibleFactory implements Factory{
@Override
public Vehicle makeVehicle() {
return new Convertible();
}
}
public class User {
public static Vehicle mVehicle;
public static Factory mFactory;
public static void main(String[] args) {
mFactory=new ConvertibleFactory();
mVehicle=mFactory.makeVehicle();
mVehicle.drive();
}
}
这时,生产出来的就是Convertible产品了。
设计模式的应用还是要根据其使用场景来决定,简单工厂升级为工厂方法,是因为需要封装工厂类,提供给客户类最大的自由和扩展性,但又对工厂的内部逻辑进行封装。
但不是说简单工厂就没有工厂方法好用,当客户类User本身也是内部封装的一部分,我们可以很方便的去修改工厂类,或者产品的增加可能很小,比如Phone,本来就只有GSMPhone,CDMAPhone,过了很久,突然出现了CDMALTEPhone,那也只需要在工厂类中增加这个类的生产即可。也许再出现一个新的XXXPhone也要几年之后了。
Android中的工厂方法
简单工厂
Android源码中有很多的工厂方法的使用,其中大多是静态工厂方法,也即是最开始说的简单工厂,前面也说过了,使用什么工厂是根据需求来看的,静态工厂方法是工厂方法的一个特例,虽然不似工厂方法那么灵活,但是对于很多不需要创建多个工厂来建造产品的情况下,静态工厂方法反而简单快捷。
例如BitmapFactory,通过public static Bitmap decodeFile(String pathName)静态方法,从文件中读取并新建Bitmap对象。
还比如Telephony中的PhoneFactory,通过public static void makeDefaultPhones(Context context) 静态方法创建,并通过PhoneFactory.getDefaultPhone()获取创建好的
还有NetworkStatsFactory,WebViewFactory这些都是简单工厂的应用。
除了Framework,很多系统应用也用到了工厂方法,就不一一列举了。
工厂方法
Java库中的ThreadFactory类作为抽象工厂,定义如下:
public interface ThreadFactory {
Thread newThread(Runnable r);
}
Android中常用的AsyncTask,在其中就新建了一个具体的工厂(还有MMS应用中的BackgroundLoaderThreadFactory的实现,类似):
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
ThreadFactory的使用一般用在作为新建ThreadPoolExecutor的参数,在ThreadPoolExecutor中调用getThreadFactory().newThread()来新建一个工作线程,这里面Runnable可以理解为抽象产品,而Thread则是具体产品。