工厂模式的思想目的就是为了让创建对象的过程脱离业务逻辑,将他交给一个工厂去实现
下面通过一个案例来进一步体会一下该思想
我们定义一个coffee接口
定义两个类去实现该接口
还有一个coffeestore的类用来下单咖啡,代码实现逻辑如下
可以发现,我们创建对象的过程存在业务代码里面,当我们需要新增一个咖啡品种的时候,就需要动业务代码,这样不利于维护。我们可以利用工厂思想,将对象创建的过程另置再一个工厂类中,然后再业务层调用工厂来下单咖啡,这样就能将业务层和coffee实现类解耦。
但这样又引入了工厂和实现类的耦合。
我们用工厂方法进行改进
将工厂定义成接口
然后用两个类americanoCoffeeFactory和latteCoffeeFactory去实现这个接口
用户下单时只需选择相应的咖啡工厂就可以
这样,每个咖啡都有自己对应的工厂制作,解决了工厂和实现类的耦合,这样就完全完全符合“开闭原则”。
利用工厂方法优点:当我们需要添加新的咖啡种类的时候,只需新增该产品的实现类和工厂就行,无需对代码进行改造
缺点就是每新增一个产品,都需要添加对应的产品类和工厂类,增加了系统复杂度。
如果有一个场景,当我们需要对产品进行品牌标识,一个品牌可以用多个产品,一个产品可以属于多个品牌,如果继续按上面工厂方法来实现,有N个产品,N个品牌的话,就需要创建N*N个产品类和工厂类。
从上面的解决方式可以看出:使用工厂方法模式,创建了很多具体工厂类,而没有利用产品的“商品族”的概念。
由此引出,抽象工厂模式是用于解决“一类产品”的创建问题
下面以李宁和安踏足球和篮球为场景编写代码
//抽象工厂
public interface AbstractFactory {
Basketball makeBasketball();
Football makeFootball();
}
//产品族
public interface Basketball {
void sayBasketball();
}
public interface Football {
void sayFootball();
}
public class LiningBasketball implements Basketball {
@Override
public void sayBasketball() {
System.out.println("李宁篮球");
}
}
public class LiningFootball implements Football {
@Override
public void sayFootball() {
System.out.println("李宁足球");
}
}
public class AntaBasketball implements Basketball {
@Override
public void sayBasketball() {
System.out.println("安踏篮球");
}
}
public class AntaFootball implements Football {
@Override
public void sayFootball() {
System.out.println("安踏足球");
}
}
//产品工厂
public class LiningFactoy implements AbstractFactory {
@Override
public Basketball makeBasketball() {
return new LiningBasketball();
}
@Override
public Football makeFootball() {
return new LiningFootball();
}
}
public class AntaFactory implements AbstractFactory {
@Override
public Basketball makeBasketball() {
return new AntaBasketball();
}
@Override
public Football makeFootball() {
return new AntaFootball();
}
}
public class Main{
public static void main(String[] args){
// 生产李宁篮球和安踏足球
LiningFactoy liningFactoy = new LiningFactoy();
AntaFactory antaFactory = new AntaFactory();
liningFactoy.makeBasketball().sayBasketball();
antaFactory.makeFootball().sayFootball();
}
和上面工厂方法不同,抽象工厂方法只有在新增一个新的品牌产品的时候才会新增一个工厂,