设计模式—创建者模式之工厂模式
1. 看一个问题(引入)
假设现在有一个接口,有一个实现类实现了它,客户端怎么使用它呢?
如图,首先创建一个实例BaseApiImpl,赋值给一个BaseApi接口类型的变量,通过这个变量来操作接口。
代码如下:
public interface BaseApi {
public void testString(String s);
}
public class BaseApiImpl implements BaseApi{
@Override
public void testString(String s) {
System.out.println("string是:"+s);
}
}
public class Client {
public static void main(String[] args) {
/**
* 不符合接口隔离原则
*/
BaseApi baseApi = new BaseApiImpl();//在Client可以直接看见接口和实现类
baseApi.testString("我是XXX");
}
}
思考:
- 上述代码实先了这样一个功能,但是又一个问题,就是在Client客户端可以直接看见接口和实现类,不符合接口隔离原则
- 怎么改进呢?也许可以
new BaseApiImpl()
移入工厂内。
2. 简单工厂模式
以上,假设现在有一个水果店,买苹果和香蕉,怎么实现呢。
如类图,
- 我们可以创建一个抽象接口FruitApi,在实现这样一个接口。
- 每一个产品对应一个具体类,如Apple、Banana。
- 创建一个具体的工厂,将
new Apple()、new Banana()
移入工厂内 - 客户端Client使用。
代码如下:
//抽象接口FruitApi
public interface FruitApi {
public void sell(String s);
}
//具体类Apple
public class Apple implements FruitApi {
@Override
public void sell(String s) {
System.out.println(s+"我买的是苹果");
}
}
//具体类 Banana
public class Banana implements FruitApi{
@Override
public void sell(String s) {
System.out.println(s+"我买的是香蕉");
}
}
//具体工厂Factory
public class Factory {
public static FruitApi getFruitService(int condition){
FruitApi fruitApi = null;
if (condition == 1) {
fruitApi = new Apple();
}else if (condition == 2) {
fruitApi = new Banana();
}
return fruitApi;
}
}
//客户Client
public class Client {
public static void main(String[] args) {
FruitApi fiurtApi = Factory.getFruitService(1);
fiurtApi.sell("我正在买水果:");
}
}
思考:
- 相较与开始的问题导入,简单工厂模式中客户端不知道具体实现的是什么,只需要通过工厂获取一个接口对象,通过操作接口对象来实现自己想要的功能。
- 但是当需要新增产品时,比如要买菠萝,那么就需要修改Factory中的代码,不符合开闭原则。
3.工厂方法模式
基于以上思考,就有了工厂方法模式。
如类图,
- 我们在第简单工厂模式的基础上加入了一个抽象工厂Factory。
- 每一个产品对应一个具体的工厂类如AppleFactory、BananaFactory
代码如下:
//抽象接口FruitApi
public interface FruitApi {
public void sell(String s);
}
//具体类Apple
public class Apple implements FruitApi {
@Override
public void sell(String s) {
System.out.println(s+"我买的是苹果");
}
}
//具体类 Banana
public class Banana implements FruitApi{
@Override
public void sell(String s) {
System.out.println(s+"我买的是香蕉");
}
}
//抽象工厂Factory
public interface Factory {
FruitApi sellFruit();
}
//具体工厂AppleFactory
public class AppleFactory implements Factory{
@Override
public FruitApi sellFruit() {
return new Apple();
}
}
//具体工厂BananaFactory
public class BananaFactory implements Factory{
@Override
public FruitApi sellFruit() {
return new Banana();
}
}
//客户Client
public class Client {
public static void main(String[] args) {
Factory factory = new BananaFactory();
factory.sellFruit().sell("我买了水果:");
Factory factory1 = new AppleFactory();
factory1.sellFruit().sell("我买了水果:");
}
}
思考:
- 一般工厂方法返回的是被创建对象的接口对象,在设计的时候,不需要考虑抽象工厂具体的功能,只要在用的时候返回需要的对象即可。
- 如果要加入一个新的产品(菠萝),只需要新建一个菠萝具体类和菠萝具体工厂,不需要改变抽象工厂。
- 假设现在我需要加入一个新的产品簇,比如水果汁,我该怎么实现呢?
4.抽象工厂模式
基于以上思考。
如类图:
- 在工厂方法模式的基础上添加一个新的产大类JuiceApi
- 同样每一个产品对应一个实现类AppleJuice、BananaJuice
- 在抽象工厂以及具体工厂类中添加相应的代码。
代码如下:
//抽象接口FruitApi
public interface FruitApi {
public void sell(String s);
}
//具体类Apple
public class Apple implements FruitApi {
@Override
public void sell(String s) {
System.out.println(s+"我买的是苹果");
}
}
//具体类 Banana
public class Banana implements FruitApi{
@Override
public void sell(String s) {
System.out.println(s+"我买的是香蕉");
}
}
//抽象接口JuiceApi
public interface JuiceApi {
void sellJuice(String s);
}
//具体类 AppleJuice
public class AppleJuice implements JuiceApi {
@Override
public void sellJuice(String s) {
System.out.println(s+"我买的是苹果汁");
}
}
//具体类 BananaJucie
public class BananaJucie implements JuiceApi{
@Override
public void sellJuice(String s) {
System.out.println(s+"我买的是苹果汁");
}
}
//抽象工厂Factory
public interface Factory {
FruitApi sellFruit();
JuiceApi sellJuice();
}
//具体工厂AppleFactory
public class AppleFactory implements Factory{
@Override
public FruitApi sellFruit() {
return new Apple();
}
@Override
public JuiceApi sellJuice() {
return new AppleJuice();
}
}
//具体工厂BananaFactory
public class BananaFactory implements Factory{
@Override
public FruitApi sellFruit() {
return new Banana();
}
@Override
public JuiceApi sellJuice() {
return new BananaJucie();
}
}
//客户Client
public class Client {
public static void main(String[] args) {
Factory factory = new BananaFactory();
factory.sellFruit().sell("我买了水果:");
Factory factory1 = new AppleFactory();
factory1.sellFruit().sell("我买了水果:");
}
}
思考:
- 抽象工厂模式为一系列的相关对象(产品簇)创建一个接口
- 但是当需要新增一个产品簇的时候,需要修改抽象工厂以及所有具体工厂的代码,从这个方面上讲,不符合开闭原则。
5.总结
- 简单工厂模式就是创建了多个实例化的类。
- 工厂方法模式相较与简单工厂模式,加了一个抽象工厂的概念。一个产品对应一个具体的工厂类。
- 抽象工厂模式相较与工厂方法模式,在工厂方法模式的基础上添加了一个产品簇。但是当需要在添加一个新的产品簇的时候,需要修改抽象工厂以及所有具体工厂类的代码,违反开闭原则。
- 当抽象工厂模式的产品簇只有一种时,即为工厂方法模式。抽象工厂模式是工厂方法模式的一种拓展
- 设计模式只是一种指导思想,具体使用哪种,根据实际情况来进行分析。