设计模式之抽象工厂模式

138 阅读3分钟

工厂方法模式一文中,使用女娲造人的案例介绍了工厂方法模式的思想和简单实现,还是使用同样的案例,但创造的人类的粒度更细,除了肤色以外,还要区分性别。

Human相关的类图:

在这个类图中:

  • Human接口称为Product产品类
  • 3个抽象类称为产品等级
  • 6个实现类叫做产品族

工厂相关的类图:

  • 抽象工厂中只实现了createHuman()方法,目的是简化实现类的代码量
  • 这里用到的Enum类型使用类的静态变量来替换也没有任何问题

完整的类图如下:

产品相关的代码:

public interface Human {
    
    // 人会笑
    void laugh();
    
    // 人会哭
    void cry();
    
    // 人会说话
    void talk();
    
    // 定义性别
    void sex();
    
}

public abstract class YellowHuman implements Human {

    @Override
    public void laugh() {
        System.out.println("黄种人会笑...");
    }

    @Override
    public void cry() {
        System.out.println("黄种人会哭...");
    }

    @Override
    public void talk() {
        System.out.println("黄种人说话...";
    }

}

public abstract class WhiteHuman implements Human {

    @Override
    public void laugh() {
        System.out.println("白种人会笑...");
    }

    @Override
    public void cry() {
        System.out.println("白种人会哭...");
    }

    @Override
    public void talk() {
        System.out.println("白种人说话...");
    }

}

public abstract class BlackHuman implements Human {

    @Override
    public void laugh() {
        System.out.println("黑种人会笑...");
    }

    @Override
    public void cry() {
        System.out.println("黑种人会哭...");
    }

    @Override
    public void talk() {
        System.out.println("黑种人说话...");
    }

}

/**
 * @Description: 女性黄种人
 */
public class YellowFemaleHuman extends YellowHuman {

    @Override
    public void sex() {
        System.out.println("女性黄种人...");
    }

}

/**
 * @Description: 男性黄种人
 */
public class YellowMaleHuman extends YellowHuman {

    @Override
    public void sex() {
        System.out.println("男性黄种人...");
    }

}

/**
 * @Description: 女性白种人
 */
public class WhiteFemaleHuman extends YellowHuman {

    @Override
    public void sex() {
        System.out.println("女性白种人...");
    }

}

/**
 * @Description: 男性白种人
 */
public class WhiteMaleHuman extends YellowHuman {

    @Override
    public void sex() {
        System.out.println("男性白种人...");
    }

}

/**
 * @Description: 女性黑种人
 */
public class BlackFemaleHuman extends YellowHuman {

    @Override
    public void sex() {
        System.out.println("女性黑种人...");
    }

}

/**
 * @Description: 男性黑种人
 */
public class BlackMaleHuman extends YellowHuman {

    @Override
    public void sex() {
        System.out.println("男性黑种人...");
    }

}

3个抽象类之所以使用抽象类,是因为:

  • sex() 方法无需实现
  • 不允许直接new这3个类

工厂相关的代码:

/**
 * @Description: 列出所有Human的具体实现,Enum类型简单易用,尽量不要使用多态、继承等方法
 * 使用Enum类的好处:Enum类型作为一个参数传递到一个方法中,当使用Junit进行单元测试时
 * 不用判断输入参数是否为空、长度为0等边界异常条件
 * 如果方法传入的参数不是Enum类型的话,无法传入
 */
public enum HumanEnum {

    YellowMaleHuman("com.a.b.YellowMaleHuman"),
    YellowFemaleHuman("com.a.b.YellowFemaleHuman"),
    WhiteMaleHuman("com.a.b.WhiteMaleHuman"),
    WhiteFemaleHuman("com.a.b.WhiteFemaleHuman"),
    BlackMaleHuman("com.a.b.BlackMaleHuman"),
    BlackFemaleHuman("com.a.b.BlackFemaleHuman");
    
    private String value = "";
    
    private HumanEnum(String value){
        this.value = value;
    } 
    
    public String getValue(){
        return this.value;
    } 
    
}

/**
 * @Description: 工厂接口
 */
public interface HumanFactory {

    // 制造黄种人
    Human createYellowHuman();
    
    // 制造白种人
    Human createWhiteHuman();
    
    // 制造黑种人
    Human createBlackHuman();
    
}

/**
 * @Description: 抽象类,根据Enum类型创建Human实例
 */
public abstract class AbstractHumanFactory implements HumanFactory {

    // 给定一个性别人种,创建一个人类出来 专业术语是产生产品等级
    protected Human createHuman(HumanEnum humanEnum) {
        Human human = null; 
        // 如果传递进来不是一个Enum中具体的一个Element的话,则不处理
        if(!humanEnum.getValue().equals("")) {
            try {
                human = (Human) Class.forName(humanEnum.getValue()).newInstance();
            } catch (Exception e) {
                // 因为使用了Enum,这个种异常情况不会产生了,除非Enum的定义有问题
                e.printStackTrace();
            }
        }
        return human;
    }

}

/**
 * @Description: 男性创建工厂
 */
public class MaleHumanFactory extends AbstractHumanFactory {

    // 创造男性黄种人
    @Override
    public Human createYellowHuman() {
        return super.createHuman(HumanEnum.YellowMaleHuman);
    }

    // 创造男性白种人
    @Override
    public Human createWhiteHuman() {
        return super.createHuman(HumanEnum.WhiteMaleHuman);
    }

    // 创造男性黑种人
    @Override
    public Human createBlackHuman() {
        return super.createHuman(HumanEnum.BlackMaleHuman);
    }

}

/**
 * @Description: 女性创建工厂
 */
public class FemaleHumanFactory extends AbstractHumanFactory {

    // 创造女性黄种人
    @Override
    public Human createYellowHuman() {
        return super.createHuman(HumanEnum.YellowFemaleHuman);
    }

    // 创造女性白种人
    @Override
    public Human createWhiteHuman() {
        return super.createHuman(HumanEnum.WhiteFemaleHuman);
    }

    // 创造女性黑种人
    @Override
    public Human createBlackHuman() {
        return super.createHuman(HumanEnum.BlackFemaleHuman);
    }

}

客户端调用代码:

/**
 * @Description: 两条生产线:男性生产线和女性生产线
 */
public class NvWa {

    public static void main(String[] args) {
        // 男性生产线
        HumanFactory maleHumanFactory = new MaleHumanFactory();

        // 女性生产线
        HumanFactory femaleHumanFactory = new FemaleHumanFactory(); 
        
        Human maleYellowHuman = maleHumanFactory.createYellowHuman();
        Human femaleYellowHuman = femaleHumanFactory.createYellowHuman();

        maleYellowHuman.cry();
        maleYellowHuman.laugh();
        femaleYellowHuman.sex();
        
        // ...
        
    }
    
}

可以看到,工厂模式(包括工厂方法模式和抽象工厂模式),他们都实现了高内聚低耦合的设计思想,符合开闭原则。抽象工厂模式更是如此,如果要在产品族中增加一类产品,只需要增加一个产品实现类和一个工厂实现类即可。在一个项目中,只需要对外开发产品接口和工厂实现类即可让客户端创建需要的实例对象。

本文原书:《您的设计模式》作者:CBF4LIFE