概念
抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
工厂方法是有一个类型的产品,也就是只有一个产品的抽象类或接口,而抽象工厂相对于工厂方法来说,是有n个类型的产品,也就具有n个产品的抽象类或接口。通俗的来讲,就是由生成一个类型的产品转变为生成一组产品,这是二者的主要区别,两个的相同点是抽象的工厂接口里关联的永远是抽象的产品。
结构
抽象工厂的类图如下:
AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品(抽象的产品)。
ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品。
AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
实例
现在有海尔和海信两家公司,都会生产电视和空调,根据这种场景,我们可以拆分一下,把电视和空调作为产品族,海尔和海信两家公司作为两个生产产品的抽象工厂,它们都可以生产电视和空调。
空调的抽象产品:
public interface HVAC {
void displayHVAC();
}
海尔空调:
public class HaierHVAC implements HVAC {
@Override
public void displayHVAC() {
System.out.println("海尔空调");
}
}
海信空调:
public class HisenseHAVC implements HVAC{
@Override
public void displayHVAC() {
System.out.println("海信空调");
}
}
电视的抽象产品:
public interface TV {
void displayTV();
}
海尔电视:
public class HaierTV implements TV{
@Override
public void displayTV() {
System.out.println("海尔电视");
}
}
海信电视:
public class HisenseHAVC implements HVAC{
@Override
public void displayHVAC() {
System.out.println("海信空调");
}
}
抽象的工厂,海信工厂和海尔工厂实现该接口:
public interface AbstractFactory {
TV createTV();
HVAC createHVAC();
}
海尔工厂:
public class HaierFactory implements AbstractFactory{
@Override
public TV createTV() {
return new HaierTV();
}
@Override
public HVAC createHVAC() {
return new HaierHVAC();
}
}
海信工厂:
public class HisenseFactory implements AbstractFactory {
@Override
public TV createTV() {
return new HisenseTV();
}
@Override
public HVAC createHVAC() {
return new HisenseHAVC();
}
}
客户端实现:
public class Client {
public static void main(String[] args) {
//创建海尔的空调和电视
AbstractFactory haierFactory = new HaierFactory();
TV haierTV = haierFactory.createTV();
HVAC haierHVAC = haierFactory.createHVAC();
haierTV.displayTV();
haierHVAC.displayHVAC();
}
}
结果:
优化
抽象工厂比工厂方法多了一个产品族的抽象,也就是可以在工厂里创建多个产品。当新的公司介入时,如长虹公司也来了,那就在实现一个长虹公司的工厂,实现抽象工厂,然后重写里面的方法即可。
但是假如海尔和海信不仅仅生产空调和电视了,还想生产冰箱,那就需要再增加一个产品,这时,海尔和海信工厂都需要增加一个生产冰箱的方法,假如有n个像海尔和海信这样的工厂,那每个工厂都需要重写方法,很难扩展。
于是我苦思冥想,终于想到了一个方案,先说下思路:
1、因为当扩展新的产品时,就要重写工厂的方法,所以这个工厂里,我打算只放一个获取产品的方法,返回类型是一个抽象的产品。
2、要实现完全的开闭原则不太现实,只能减少对原有类的影响,要改的话只改动一个类就好,所以可以把需要变动的地方都放到一个类中,需要变动的点就是扩展新的产品。
3、因为客户面向的是抽象,所以在客户端不能出现具体的产品,只能出现抽象产品,但是可以通过字符串的形式进行传参,这样与每个类都没有耦合。
4、因为海尔和海信的工厂是固定的,可以在里面出现魔法值。
下面是优化的效果:
抽象工厂类,只有一个抽象的方法:
public interface AbstractFactory {
Product create(String type);
}
海尔工厂类,可通过反射获取具体的产品:
public class HaierFactory implements AbstractFactory {
@Override
public Product create(String type) {
Map<String, String> productClassNameByType = ExtendUtil.getProductClassNameByType(type);
String className = productClassNameByType.get("haier");
Object o = null;
try {
o = Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (Product) o;
}
}
海信工厂类:
public class HisenseFactory implements AbstractFactory {
@Override
public Product create(String type) {
Map<String, String> productClassNameByType = ExtendUtil.getProductClassNameByType(type);
String className = productClassNameByType.get("hisense");
Object o = null;
try {
o = Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (Product) o;
}
}
一个工具类,用来扩展使用,存放产品族和具体产品之间的关系:
public class ExtendUtil {
private static Map<String, Map<String, String>> map = new HashMap<>();
static {
map = new HashMap<String, Map<String, String>>() {{
Map<String, String> tvMap = new HashMap<>();
tvMap.put("haier", "com.tfjybj.ming.design.absfactory.HaierTV");
tvMap.put("hisense", "com.tfjybj.ming.design.absfactory.HisenseTV");
put("tv", tvMap);
Map<String, String> hvacMap = new HashMap<>();
hvacMap.put("haier", "com.tfjybj.ming.design.absfactory.HaierHVAC");
hvacMap.put("hisense", "com.tfjybj.ming.design.absfactory.HisenseHVAC");
put("hvac", hvacMap);
}};
}
public static Map<String,String> getProductClassNameByType(String type){
return map.get(type);
}
}
最抽象的产品:
public interface Product {
void display();
}
海尔电视:
public class HaierTV implements Product {
@Override
public void display() {
System.out.println("海尔电视");
}
}
海尔空调:
public class HaierHVAC implements Product {
@Override
public void display() {
System.out.println("海尔空调");
}
}
海信电视:
public class HisenseTV implements Product {
@Override
public void display() {
System.out.println("海信电视");
}
}
海信空调:
public class HisenseHAVC implements Product{
@Override
public void display() {
System.out.println("海信空调");
}
}
客户端使用:
public class Client {
public static void main(String[] args) {
//创建海尔的空调和电视
AbstractFactory haierFactory = new HaierFactory();
//客户端面向的是抽象
Product tv = haierFactory.create("tv");
Product hvac = haierFactory.create("hvac");
tv.display();
hvac.display();
}
}
如果增加新的产品如冰箱,或者新增工厂如长虹电器,则需要改动的地方只有这里:
欢迎您的观看,有问题一起探讨。