设计模式之工厂模式

设计模式之工厂模式

学Spring的时候常常听说到工厂模式,什么BeanFactory大都听过一点

描述的结构

  • 引入
  • 简单工厂模式的两种实现
  • 工厂模式的实现
  • 抽象工厂的实现

引入

工厂模式到底是什么呢?
看下面代码:(比较繁琐。不想看直接跳过!!!)

public class RuleConfigSource {
  public RuleConfig load(String ruleConfigFilePath) {
    String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
    IRuleConfigParser parser = null;
    if ("json".equalsIgnoreCase(ruleConfigFileExtension)) {
      parser = new JsonRuleConfigParser();
    } else if ("xml".equalsIgnoreCase(ruleConfigFileExtension)) {
      parser = new XmlRuleConfigParser();
    } else if ("yaml".equalsIgnoreCase(ruleConfigFileExtension)) {
      parser = new YamlRuleConfigParser();
    } else if ("properties".equalsIgnoreCase(ruleConfigFileExtension)) {
      parser = new PropertiesRuleConfigParser();
    } else {
      throw new InvalidRuleConfigException(
             "Rule config file format is not supported: " + ruleConfigFilePath);
    }

    String configText = "";
    //从ruleConfigFilePath文件中读取配置文本到configText中
    RuleConfig ruleConfig = parser.parse(configText);
    return ruleConfig;
  }

  private String getFileExtension(String filePath) {
    //...解析文件名获取扩展名,比如rule.json,返回json
    return "json";
  }
}

为了让代码逻辑更加清晰,可读性更好,我们要善于将功能独立的代码块封装成函数。按照这个设计思路,我们可以将代码中涉及 parser 创建的部分逻辑剥离出来,抽象成 createParser() 函数。重构之后的代码如下所示:

  public RuleConfig load(String ruleConfigFilePath) {
    String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
    IRuleConfigParser parser = createParser(ruleConfigFileExtension);
    if (parser == null) {
      throw new InvalidRuleConfigException(
              "Rule config file format is not supported: " + ruleConfigFilePath);
    }

    String configText = "";
    //从ruleConfigFilePath文件中读取配置文本到configText中
    RuleConfig ruleConfig = parser.parse(configText);
    return ruleConfig;
  }

  private String getFileExtension(String filePath) {
    //...解析文件名获取扩展名,比如rule.json,返回json
    return "json";
  }

  private IRuleConfigParser createParser(String configFormat) {
    IRuleConfigParser parser = null;
    if ("json".equalsIgnoreCase(configFormat)) {
      parser = new JsonRuleConfigParser();
    } else if ("xml".equalsIgnoreCase(configFormat)) {
      parser = new XmlRuleConfigParser();
    } else if ("yaml".equalsIgnoreCase(configFormat)) {
      parser = new YamlRuleConfigParser();
    } else if ("properties".equalsIgnoreCase(configFormat)) {
      parser = new PropertiesRuleConfigParser();
    }
    return parser;
  }
}

为了让类的职责更加单一(设计模式原则中的单一职责,)、代码更加清晰,我们还可以进一步将 createParser() 函数剥离到一个独立的类中,让这个类只负责对象的创建。而这个类就是我们现在要讲的简单工厂模式类。

简单工厂模式

为了便于理解我们就用一个简单的例子来试验一下

现在我们有一个Shape接口 里面只有一个方法就是画画的方法

在这里插入图片描述


public interface Shape {
    public  void draw();
}

然后我们有他的实现类 Y(圆)Z(正方型)

public class Y implements Shape{
    @Override
    public void draw() {
        System.out.println("Y");
    }
}
public class Z implements Shape{
    @Override
    public void draw() {
        System.out.println("z");
    }
}

现在我们有一个工厂类来负责实例化对象

public class Factory {
  public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        }if (shapeType.equals("Y")) {
            return new Y();
        }if (shapeType.equals("Z")){
            return new Z();
        }return null;
     }
}

这样的话我们对于对象的获取就非常方便了,我们直接调用工厂类就可以进行获取,这也是简单工厂模式的第一种实现方式。
但是问题来了,如果我们需要添加一个类的话,需要改的代码实在是太多了

如果 可以复用,为了节省内存和对象创建的时间,我们可以将这些Shape事先创建好缓存起来。当调用 getShape() 函数的时候,我们从缓存中取出 Shape 对象直接使用。这有点类似单例模式和简单工厂模式的结合

import java.util.HashMap;
import java.util.Map;

public class Factory {

    private static final Map<String, Object> map = new HashMap<String, Object>();

    static {
        map.put("Y", new Y());
        map.put("Z", new Z());
    }

    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        Shape shape = (Shape) map.get(shapeType);
        return shape;

    }
}

我们把上一种实现方法叫作简单工厂模式的第二种实现方法。

  • 对于上述的两种工厂模式,我们如果需要添加一个类,我们需要修改的东西太多了,那么这符合我们开闭原则吗?实际上,如果不是频繁的修改代码,偶尔修改一下,不满足开闭原则,我们也是可以接受的。
  • 除此之外,在第一种代码实现中,有一组 if 分支判断逻辑,是不是应该用多态或其他设计模式来替代呢?实际上,如果 if 分支并不是很多,代码中有 if 分支也是完全可以接受的。应用多态或设计模式来替代 if 分支判断逻辑,也并不是没有任何缺点的,它虽然提高了代码的扩展性,更加符合开闭原则,但也增加了类的个数,牺牲了代码的可读性。
  • 总结一下,尽管简单工厂模式的代码实现中,有多处 if 分支判断逻辑,违背开闭原则,但权衡扩展性和可读性,这样的代码实现在大多数情况下(比如,不需要频繁地添加 parser,也没有太多的 Shape)是没有问题的。

工厂方法

如果我们非得要将 if 分支逻辑去掉,那该怎么办呢?比较经典处理方法就是利用多态:这里我们使用人类来表示,分为黑人和白人

黑人和白人

这里有一个人的大类接口
public interface human {
    public void say();
}

然后有两个他的实现类

黑人


public class BlackHuman implements human {
    @Override
    public void say() {
        System.out.println("i am a black human");
    }
}

白人

public class WhiteHuman implements human{
    @Override
    public void say() {
        System.out.println("I am a white human");
    }
}

然后们的工厂类

public abstract class AbstractHumanFactory {
    public abstract human createHuman();
}

继承两个工厂类的(子工厂)类
黑人工厂

public class BlackHumanFactory extends AbstractHumanFactory{
    @Override
    public human createHuman() {
        return new BlackHuman();
    }
}

白人工厂

public class WhiteHumanFactory extends AbstractHumanFactory{
    @Override
    public human createHuman() {
        return new WhiteHuman();
    }
}

测试类

    public class Test {
        public static void main(String[] args) {
            AbstractHumanFactory abstractHumanFactory = null;
            abstractHumanFactory = new BlackHumanFactory();
            BlackHuman blackHuman = (BlackHuman) abstractHumanFactory.createHuman();
            blackHuman.say();
    
            abstractHumanFactory = new WhiteHumanFactory();
            WhiteHuman whiteHuman = (WhiteHuman) abstractHumanFactory.createHuman();
            whiteHuman.say();
        }
    }

这样的实现方法在如果我们想增加一个黄种人进去,那么我们只需要实现一个Human大类的接口和集成Factory的子工厂就可以了,这样的话就大大的解耦了
所以,工厂方法模式比起简单工厂模式更加符合开闭原则。

抽象工厂方法

在简单工厂和工厂方法中,类只有一种分类方式。
但是,如果类有两种分类方式呢?
比如我们的黑人和白人分别还分为男人和女人

  • 这就引出了我们的抽象工厂方法

抽象工厂方法

在这种方法中,我们还是有一个大类Human

public interface Human {
    void printColor();
}

它的两个抽象实现方法(注意抽象)
Man和WoMan

public abstract class Man implements Human {

    public void printGender() {
        System.out.println("I am a  man");
    }
    @Override
    public abstract void printColor();
}

public abstract class WoMan implements Human{

    public void printGender(){
        System.out.println("i am a woman");
    }

    @Override
    public abstract void printColor();
}

在man和woman的分类下当然还有之前的黑和白

Man下的子类


public class BlackMan extends Man{
    @Override
    public void printColor() {
        System.out.println("i am blackColor");
    }
}

public class WhiteMan extends Man {
    @Override
    public void printColor() {
        System.out.println("I am white Color");
    }
}

WoMan下的子类

public class BlackWoman extends WoMan{
    @Override
    public void printColor() {
        System.out.println("I am black Color");
    }
}

public class WhiteWoman extends WoMan {
    @Override
    public void printColor() {
        System.out.println("i am white color");
    }
}

当然还有我们的工厂类

public abstract class AbstractHumanFactory {

    public abstract Man createMan();

    public abstract WoMan createWoman();

}

黑人的(子工厂)


public class BlackHumanFactory extends AbstractHumanFactory{
    @Override
    public Man createMan() {
        return new BlackMan();
    }

    @Override
    public WoMan createWoman() {
        return new BlackWoman();
    }
}

白人的(子工厂)

public class WhiteHumanFactory extends AbstractHumanFactory{
    @Override
    public Man createMan() {
        return new WhiteMan();
    }

    @Override
    public WoMan createWoman() {
        return new WhiteWoman();
    }
}

最后测试一下

public class test {
    public static void main(String[] args) {
        AbstractHumanFactory factory = null;

        factory = new BlackHumanFactory();
        BlackMan blackMan = (BlackMan) factory.createMan();
        blackMan.printColor();
        blackMan.printGender();
        BlackWoman blackWoman = (BlackWoman) factory.createWoman();
        blackWoman.printColor();
        blackWoman.printGender();


        factory = new WhiteHumanFactory();
        WhiteMan whiteMan = (WhiteMan) factory.createMan();
        whiteMan.printColor();
        whiteMan.printGender();
        WhiteWoman whiteWoman = (WhiteWoman) factory.createWoman();
        whiteWoman.printColor();
        whiteWoman.printGender();
    }
}

这就是整个的实现过程了

那么看完之后我们发现了什么呢?

再看一遍抽象工厂的类图关系
在这里插入图片描述
0、 在这里我们可以清楚的看到,如果我们想要获取一个BlackMan对象,那么我们只需要调用BlackHumanFactory这个工厂就行了,我们不需要去了解他的实现。

1、 在我们想要加入一个新的颜色的人,我们也不必去管其他的类,例如这里的黑人和白人。换个方式讲,黑人和白人放在这里很稳定,测试通过后就可以不必去改动它,如果我们想要增加,只需要实现对应的方法,测试新实现的就好了

2、工厂模式虽然麻烦,但是耦合度可以大大的降低,这是目前我认为工厂模式最大的好处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值