为何使用工厂模式创建对象而不是直接new
- 降低代码之间的耦合性
- 方便扩展和修改。举个例子:当前我创建了狗的对象,而且在代码中多处创建。那么需求修改了,我们需要将创建狗的对象都修改成猫。那么我们需要到程序中所有地方查找,修改。解决:创建一个动物的工厂,我们只需要配置一个字符串比如说狗,然后程序读取这个字符串从工厂中得到这个狗都对象。当我们修改的时候 ,我们只需要在工厂中添加一个猫的对象,然后修改配置的字符串为猫,这样工厂就会返回猫,其他所有用到读取配置然后创建对象的地方就直接拿到的是猫了。
- 客户端在调用时不想判断来实例化哪一个类或者实例化的过程过于复杂。在工厂模式中,具体的实现类创建过程对客户端是透明的客户端不需要管如何实现,客户端不决定具体实例化哪一个类,而是交由“工厂”来实例化。
简单工厂模式
定义
工厂模式提供了一种创建对象的最佳方式,我们在创建对象时不会对客户端暴露创建逻辑。简单来说就是定一个专门创建对象的工厂,我们把参数给他,然后他去产生相应对象。
代码实例
- 创建键盘接口,包含打印和输出方法。
- 创建不同键盘类继承接口,比如惠普和戴尔,他们实现各自的打印和输出功能
- 创建工厂类,提供一个方法,根据传入的字符串来决定创建哪个键盘对象并返回
- 使用:创建对象,然后传入参数,使用多态接收惠普键盘对象,调用方法。
public interface Keyboard {
void print();
void input(Context context);
}
class HPKeyboard implements Keyboard {
@Override
public void print() {
//...输出逻辑;
}
@Override
public void input(Context context) {
//...输入逻辑;
}
}
class DellKeyboard implements Keyboard {
@Override
public void print() {
//...输出逻辑;
}
@Override
public void input(Context context) {
//...输入逻辑;
}
}
class LenovoKeyboard implements Keyboard {
@Override
public void print() {
//...输出逻辑;
}
@Override
public void input(Context context) {
//...输入逻辑;
}
}
/**
* 工厂
*/
public class KeyboardFactory {
public Keyboard getInstance(int brand) {
if(BrandEnum.HP.getCode() == brand){
return new HPKeyboard();
} else if(BrandEnum.LENOVO.getCode() == brand){
return new LenovoKeyboard();
} else if(BrandEnum.DELL.getCode() == brand){
return new DellKeyboard();
}
return null;
}
//测试
public static void main(String[] args) {
KeyboardFactory keyboardFactory = new KeyboardFactory();
Keyboard lenovoKeyboard = KeyboardFactory.getInstance(BrandEnum.LENOVO.getCode());
//...
}
}
优点
- 一个调用者想创建一个对象,只要知道其名称就可以了。 创建简单。
- 屏蔽产品的具体实现
缺点
- 这种做法扩展性差,违背了开闭原则,也影响了可读性。每次增加一个类,就要在工厂中增加修改对象方法。可读性差。
工厂模式
定义
为了解决上面提到的"增加if-else"的问题,可以为每一个键盘子类建立一个对应的工厂子类。这样,创建不同品牌的键盘,只需要实现不同的工厂子类。当有新品牌加入时,新增具体工厂继承抽象工厂,而不用修改任何一个类。遵循开闭原则,扩展开放,修改关闭。
代码实例
- 创建一个键盘工厂
- 不同品牌键盘工厂创建自己的对象,就不需要一个公共的创建对象的工厂了。
public interface IKeyboardFactory {
Keyboard getInstance();
}
public class HPKeyboardFactory implements IKeyboardFactory {
@Override
public Keyboard getInstance(){
return new HPKeyboard();
}
}
public class LenovoFactory implements IKeyboardFactory {
@Override
public Keyboard getInstance(){
return new LenovoKeyboard();
}
}
public class DellKeyboardFactory implements IKeyboardFactory {
@Override
public Keyboard getInstance(){
return new DellKeyboard();
}
}
优点
工厂模式同样体现了开闭原则,之后想要新增产品时,只需要扩展相应工厂类的实现即可。而不需要修改原用代码。
缺点
每一种品牌对应一个工厂子类,在创建具体键盘对象时,实例化不同的工厂子类。如果增加子品牌类的话,就要增加相应工厂。这样会使得系统中类的个数成倍增加,增加了代码的复杂度。
抽象工厂模式
他是工厂模式的大规模化。
当我们有多个产品时,也就是有键盘,鼠标,显示器的时候。
抽象工厂是一个产品族的实现。工厂模式是在单一品牌产品下创建该产品工厂,而是抽象工厂模式,对每个品牌下面的产品族创建一个工厂,比如惠普品牌下有键盘,显示器,鼠标共同在一个工厂中创建对象。这样我们就可以通过某个品牌工厂创建一个产品族的所有产品。
代码实现
- 创建抽象键盘类以及各品牌键盘子类,实现打印功能
- 创建抽象鼠标类以及各品牌鼠标子类,实现移动功能。
- 创建抽象显示器类以及各品牌显示器,实现现实功能。
- 抽象工厂类:提供各种品牌创建的抽象,并提供抽象创建各种产品方法。
- 各品牌工厂类,继承抽象工厂类,提供各品牌内的各种产品的对象的创建(戴尔键盘,戴尔鼠标)。
- 客户端代码:创建戴尔工厂,然后我就可以根据需要创建戴尔工厂内各种产品的对象。
//产品1:各种键盘类
public interface Keyboard {
void print();
}
public class DellKeyboard implements Keyboard {
@Override
public void print() {
//...dell...dell;
}
}
public class HPKeyboard implements Keyboard {
@Override
public void print() {
//...HP...HP;
}
}
//产品2:各种鼠标类
public interface Monitor {
void play();
}
public class DellMonitor implements Monitor {
@Override
public void play() {
//...dell...dell;
}
}
public class HPMonitor implements Monitor {
@Override
public void play() {
//...HP...HP;
}
}
//产品3:各种显示器类
public interface MainFrame {
void run();
}
public class DellMainFrame implements MainFrame {
@Override
public void run() {
//...dell...dell;
}
}
public class HPMainFrame implements MainFrame {
@Override
public void run() {
//...HP...HP;
}
}
//抽象工厂类:提供各种品牌创建的抽象
public interface IFactory {
MainFrame createMainFrame();
Monitor createMainFrame();
Keyboard createKeyboard();
}
//各种工厂类:分为Dell工厂和HP工厂,各自负责品牌内产品的创建
public class DellFactory implements IFactory {
@Override
public MainFrame createMainFrame(){
MainFrame mainFrame = new DellMainFrame();
//...造一个Dell主机;
return mainFrame;
}
@Override
public Monitor createMonitor(){
Monitor monitor = new DellMonitor();
//...造一个Dell显示器;
return monitor;
}
@Override
public Keyboard createKeyboard(){
Keyboard keyboard = new DellKeyboard();
//...造一个Dell键盘;
return Keyboard;
}
}
public class HPFactory implements IFactory {
@Override
public MainFrame createMainFrame(){
MainFrame mainFrame = new HPMainFrame();
//...造一个HP主机;
return mainFrame;
}
@Override
public Monitor createMonitor(){
Monitor monitor = new HPMonitor();
//...造一个HP显示器;
return monitor;
}
@Override
public Keyboard createKeyboard(){
Keyboard keyboard = new HPKeyboard();
//...造一个HP键盘;
return Keyboard;
}
}
//客户端代码。实例化不同的工厂子类,可以通过不同的创建方法创建不同的产品
public class Main {
public static void main(String[] args) {
IFactory dellFactory = new DellFactory();
IFactory HPFactory = new HPFactory();
//创建戴尔键盘
Keyboard dellKeyboard = dellFactory.createKeyboard();
//...
}
}
优点
- 增加产品族很简单,比如再增加一个联想产品族,我们创建工厂和对应产品类。
缺点
扩展产品较复杂,比如我新增一个打印机产品,那么每个品牌都需要增加打印机产品类,每个工厂中也要增加产品实现。