工厂方法(Factory Method)
定义一个用于创建对象的接口,让子类决定实例化哪个类。Factory Method 使得一个类的实例化延迟(目的:解耦)到子类。
在软件系统中,经常会面临着创建对象的工作,由于需求变化,需要创建的对象的具体类型也会经常的变化
假设还是拿之前的文件分割器作为例子,如果不使用具体的设计模式,那么在具体创建对象的时候,需要在初始化对象的时候指定出具体的实现细节,虽然ISplitter * splitter = new BinarySplitter(); 是面向接口的编程,将变量生命为了抽象的基类,但在实际new时,依赖了一个具体的实现类。实际上这里违反了依赖导致原则。如果这时候具体的Splitter还未完成实现,那么编译时会报错,如果需求发生变更那么此时,也需要重新修改和编译源代码。
原先
// 文件分割器接口
interface ISplitter {
void split();
};
class BinarySplitter implements ISplitter {
@Override
public void split() {
}
};
// 文件分割器具体实现类
class TxtSplitter implements ISplitter {
@Override
public void split() {
}
};
// 文件分割器具体实现类
class PictureSplitter implements ISplitter {
@Override
public void split() {
}
};
// 文件分割器具体实现类
class VideoSplitter implements ISplitter {
@Override
public void split() {
}
};
public class FactoryMethod {
@Test
public void T1() {
// 对象创建依赖了具体的类
ISplitter splitter = new BinarySplitter();
splitter.split();
}
}
对于之前的代码,在应对变化时,ISplitter splitter = new BinarySplitter();这里是核心的问题。那么如何才能绕开new一个具体的细节呢?
那么我们可以使用一个函数,来讲所需要的对象返回给我们的方式来获取这个对象,为了代码的进一步隔离,我们把他直接抽象到一个新的类中,并用写成一个虚函数,由工厂的子类来自己实现创建自己的方法。也就形成了一个模式,每个实现方法有一个类,配套的每个类都有一个工厂,而这些工厂都继承自一个抽象的工厂。那么就得到了下面的代码。
重构
// 文件分割器接口
interface ISplitter {
void split();
};
class BinarySplitter implements ISplitter {
@Override
public void split() {
}
};
// 文件分割器具体实现类
class TxtSplitter implements ISplitter {
@Override
public void split() {
}
};
// 文件分割器具体实现类
class PictureSplitter implements ISplitter {
@Override
public void split() {
}
};
// 文件分割器具体实现类
class VideoSplitter implements ISplitter {
@Override
public void split() {
}
};
// 文件分割器工厂接口
interface ISplitterFactory {
ISplitter CreateSplitter();
}
// 具体工厂
class BinarySplitterFactory implements ISplitterFactory {
@Override
public ISplitter CreateSplitter() {
return null;
}
}
// 具体工厂
class TxtSplitterFactory implements ISplitterFactory {
@Override
public ISplitter CreateSplitter() {
return null;
}
}
// 具体工厂
class PictureSplitterFactory implements ISplitterFactory {
@Override
public ISplitter CreateSplitter() {
return null;
}
}
// 具体工厂
class VideoSplitterFactory implements ISplitterFactory {
@Override
public ISplitter CreateSplitter() {
return null;
}
}
public class FactoryMethod {
ISplitterFactory factory;
FactoryMethod(ISplitterFactory factory) {
this.factory = factory;
}
@Test
public void T1() {
// 多态创建对象
ISplitter splitter = factory.CreateSplitter();
splitter.split();
}
}
现在的工厂通过构造函数传入其中,依赖其实依旧存在,但是并没有具体类型的依赖,而依赖的都是接口类。其实对于设计模式来说,并没有办法消除依赖,而是将依赖控制在了最可控的地方。
总结
Factory Method 模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
Factory Method模式通过面对对象的手法,将所要创建的对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。