概述
工厂模式,顾名思义就是用来产生对象的,一般分为简单工厂模式、工厂方法模式、抽象工厂模式,严格意义上讲简单工厂不算是一种模式,它是简化版的抽象工厂模式,今天我们主要介绍一下工厂方法模式和抽象工厂模式
工厂方式模式
工厂方法模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。工厂方法模式是常用的创建类型的设计模式,在创建对象是不会向客户端暴露创建逻辑,使用共同的接口来指向新创建的对象
类图
- Dress为产品的抽象接口,定义了一个color方法
- BlackDress、YellowDress、BlueDress为具体的产品
- AbstractDressFactory为工厂的抽象,定义了创建产品的方法createDress()
- DressFactory为具体创建产品的工厂
具体实现代码
//抽象产品
public interface Dress {
public void color();
}
//具体产品BlackDress
public class BlackDress implements Dress {
@Override
public void color() {
System.out.println("Black Dress");
}
}
//具体产品YellowDress
public class YellowDress implements Dress {
@Override
public void color() {
System.out.println("Yellow Dress");
}
}
//具体产品BlueDress
public class BlueDress implements Dress {
@Override
public void color() {
System.out.println("Blue Dress");
}
}
//抽象工厂AbstractDressFactory
public interface AbstractDressFactory {
public Dress createDress(String name);
}
//具体工厂DressFactory
public class DressFactory implements AbstractDressFactory {
@Override
public Dress createDress(String name) {
if(name == null) return null;
if("Black".equalsIgnoreCase(name)){
return new BlackDress();
} else if("Yellow".equalsIgnoreCase(name)){
return new YellowDress();
} else if("Blue".equalsIgnoreCase(name)){
return new BlueDress();
}
return null;
}
}
public class Client {
public static void main(String[] args){
AbstractDressFactory factory = new DressFactory();
Dress dress = factory.createDress("Blue");
dress.color();
}
}
优缺点
优点
- 良好的封装性,代码结构清晰。调用者想要创建对象,只需要知道名称即可,不需要知道创建的具体细节,降低了模块间的耦合性
- 良好的扩展性。想增加一个产品,直接扩展一个工厂类就可以
- 屏蔽产品的具体实现,调用者只用关心产品的接口,实现模块间解耦
缺点
- 每增加一个产品类,都需要一个具体的产品类和对象实现工厂,类的数量成倍增加,一定程度增加了系统的复杂度
使用场景
- 一个连接服务,需要支持多种连接协议,比如HTTP、FTP、POP3等,可以将这些协议实现相同的接口
- 日志记录,日记记录到数据库、本地日志文件、远程服务器上,多种方式可以实现相同的接口
扩展
1.退化为简单工厂模式
假如我们只有一个模块,只需要一个工厂类,那么就不需要把工厂类进行抽象化,增加系统的复杂度,可以直接使用静态方式就可以了
简单工厂模式下的工厂类
public class SimpleDressFactory {
public static Dress createDress(String name){
if(name == null) return null;
if("Black".equalsIgnoreCase(name)){
return new BlackDress();
} else if("Yellow".equalsIgnoreCase(name)){
return new YellowDress();
} else if("Blue".equalsIgnoreCase(name)){
return new BlueDress();
}
return null;
}
}
2.扩展为多个工厂类
我们知道,是由具体的工厂类生产具体的产品的,在上面的代码中,所有的产品共用一个工厂类,可以升级为多个工厂类,各自的工厂负责生产各自的产品
public class BlackDressFactory implements AbstractDressFactory {
@Override
public Dress createDress(String name) {
return new BlackDress();
}
}
public class YellowDressFactory implements AbstractDressFactory {
@Override
public Dress createDress(String name) {
return new YellowDress();
}
}
public class BlueDressFactory implements AbstractDressFactory {
@Override
public Dress createDress(String name) {
return new BlueDress();
}
}
此时各自的工厂负责生产各自的产品,name参数已经不需要,可以修改一个工厂,这样做的好处是各司其职,自己负责生产自己的产品,但带来的代价是类的数量成倍的增加,一定程度增加了维护性和系统复杂度。
注意事项
工厂方法模式作为一种创建类型的设计模式,主要用于复杂对象的生成,简单对象的生成直接用new生成就行了,不需要使用工厂模式,如果简单的对象引入工厂方法模式,反而会增加系统的复杂度而得不偿失。任何的设计模式都是为了解决特定的问题,不同的场景我们使用不同的设计模式是为了方便以后的扩展,但我们也不能过度的设计,让原本简单的问题复杂化。
抽象工厂模式
抽象工厂模式,提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体的类。
类图
- AbstractShirt、AbstractDress为产品的抽象,他们分别有三个具体的实现
- AbstractFactory是抽象工厂类,有三个具体的工厂实现
- 每个具体的工厂都会生产自己的产品簇
具体实现代码
//抽象产品-Dress
public abstract class AbstractDress {
public abstract void color();
}
public class BlackDress extends AbstractDress {
@Override
public void color() {
System.out.println("Black Dress");
}
}
public class YellowDress extends AbstractDress {
@Override
public void color() {
System.out.println("Yellow Dress");
}
}
public class BlueDress extends AbstractDress {
@Override
public void color() {
System.out.println("Blue Dress");
}
}
public abstract class AbstractShirt {
public abstract void color();
}
//抽象产品-Shirt
public class BlackShirt extends AbstractShirt {
@Override
public void color() {
System.out.println("Black Shirt");
}
}
public class YellowShirt extends AbstractShirt {
@Override
public void color() {
System.out.println("Yellow Shirt");
}
}
public class BlueShirt extends AbstractShirt {
@Override
public void color() {
System.out.println("Blue Shirt");
}
}
//抽象工厂
public abstract class AbstractFactory {
public abstract AbstractDress createDress();
public abstract AbstractShirt createShirt();
}
public class BlackColorFactory extends AbstractFactory {
@Override
public AbstractDress createDress() {
return new BlackDress();
}
@Override
public AbstractShirt createShirt() {
return new BlackShirt();
}
}
public class YellowColorFactory extends AbstractFactory {
@Override
public AbstractDress createDress() {
return new YellowDress();
}
@Override
public AbstractShirt createShirt() {
return new YellowShirt();
}
}
public class BlueColorFactory extends AbstractFactory {
@Override
public AbstractDress createDress() {
return new BlueDress();
}
@Override
public AbstractShirt createShirt() {
return new BlackShirt();
}
}
public class Client {
public static void main(String[] args){
AbstractFactory blackFactory = new BlackColorFactory();
blackFactory.createDress().color();
blackFactory.createShirt().color();
AbstractFactory yellowFactory = new YellowColorFactory();
yellowFactory.createDress().color();
yellowFactory.createShirt().color();
AbstractFactory blueFactory = new BlueColorFactory();
blueFactory.createDress().color();
blueFactory.createShirt().color();
}
}
优缺点
优点
- 封装性,每个产品的实现类不是高层模块要关心的
- 抽象工厂模式可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理
缺点
抽象工厂模式的最大缺点就是产品族扩展非常困难,假如需要增加一个产品,需要在AbstractFactory中新增加一个create×××()方法,对应的所有具体工厂都要跟着新增这个工厂,这违背了开闭原则
抽象工厂模式使用场景
抽象工厂模式的使用场景非常简单:一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。
就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点
工厂方法与抽象工厂的比较
- 所有的工厂都是用来封装对象的,通过减少应用程序和具体的类之间的依赖来减少耦合
- 工厂方法提供一个抽象接口来创建一个产品,而抽象工厂提供一个抽象接口来创建一个产品家族
- 工厂方法使用继承来把对象的创建委托给子类,子类实现工厂方法来创建对象。而抽象工厂使用对象组合,对象的创建被实现在工厂接口所暴露出来的方法中
- 抽象工厂中往往包含有工厂方法模式
总结一下
- 工厂方法模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类
- 工厂方法模式的优点
- 良好的封装性,代码结构清晰。调用者想要创建对象,只需要知道名称即可,不需要知道创建的具体细节,降低了模块间的耦合性
- 良好的扩展性。想增加一个产品,直接扩展一个工厂类就可以
- 屏蔽产品的具体实现,调用者只用关心产品的接口,实现模块间解耦
- 工厂方法模式的缺点
- 每增加一个产品类,都需要一个具体的产品类和对象实现工厂,类的数量成倍增加,一定程度增加了系统的复杂度
- 工厂方法模式的使用场景
- 一个连接服务,需要支持多种连接协议,比如HTTP、FTP、POP3等,可以将这些协议实现相同的接口
- 日志记录,日记记录到数据库、本地日志文件、远程服务器上,多种方式可以实现相同的接口
- 扩展
- 退化为简单工厂模式
- 扩展为多个工厂类
- 注意事项:适度设计,引入设计模式是为了真正的解决问题,避免过度设计增加系统的复杂性
- 抽象工厂模式,提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体的类
- 抽象工厂模式的优点
- 封装性,每个产品的实现类不是高层模块要关心的
- 抽象工厂模式可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理
- 抽象工厂模式的缺点
- 抽象工厂模式的最大缺点就是产品族扩展非常困难
- 抽象工厂模式使用场景
- 一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式
- 工厂方法与抽象工厂的比较
- 所有的工厂都是用来封装对象的,通过减少应用程序和具体的类之间的依赖来减少耦合
- 工厂方法提供一个抽象接口来创建一个产品,而抽象工厂提供一个抽象接口来创建一个产品家族
- 工厂方法使用继承来把对象的创建委托给子类,子类实现工厂方法来创建对象。而抽象工厂使用对象组合,对象的创建被实现在工厂接口所暴露出来的方法中
- 抽象工厂中往往包含有工厂方法模式
欢迎关注Java天堂公众号,专注于Java相关技术分享