Java设计模式 之工厂模式

工厂模式思想

属于设计模式中的创建型模式。
思想: 客户指定需要的对象,把需求告诉工厂,工厂负责创建对象并返回给客户。

简单工厂模式

定义: 由一个工厂来决定创建出哪一种类的实例。不属于23种设计模式
场景: 工厂类负责创建的对象较少。
优点: 客户端只需要传入一个正确的参数,就可以获取到对应的对象,无须知道创建对象的逻辑。
缺点: 工厂类职责相对过重,增加新的产品时需要修改工厂类的判断逻辑,违背了单一职责、开闭原则。

案例代码实现:
女娲造人的故事,女娲往锅炉放泥土来进行烧制泥人,可以烧制黑种人、黄种人、白种人。
抽象出人类,有白种人、黄种人。

public interface IHuman {
    void getColor();
}
public class WhiteHuman implements IHuman {
    @Override
    public void getColor() {
        System.out.println("white human ...");
    }
}
public class YellowHuman implements IHuman {
    @Override
    public void getColor() {
        System.out.println("yellow human ...");
    }
}

创建人类的工厂,根据不同的类模板信息创建对应的人类对象。

public class HumanFactory {
    public IHuman createHuman(Class<? extends IHuman> clazz) {
        try {
            if (null != clazz) {
                return clazz.newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
public class NvWa {
    public static void main(String[] args) {
        HumanFactory humanFactory = new HumanFactory();
        IHuman whiteHuman = humanFactory.createHuman(WhiteHuman.class);
        whiteHuman.getColor();
        IHuman yellowHuman = humanFactory.createHuman(YellowHuman.class);
        yellowHuman.getColor();
    }
}

工厂方法模式

定义: 每个产品体系都有对应的工厂叫工厂模式。
工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。
场景:
优点: 新增产品只需要增加对应产品的工厂,符合开闭原则,提高了系统的扩展性。
缺点: 类的个数容易过多。

案例代码实现:
有一个汽车代工厂,客户可向工厂提交订单,客户提供对应的底盘和引擎,工厂根据订单生产汽车交付给客户。底盘是一个产品体系,引擎是一个产品体系,底盘和引擎分别对应了不同的工厂。

底盘:

// 抽象出底盘接口
public interface IChassis {
    void create();
}

// 奥迪汽车底盘
public class AudiChassis implements IChassis {
    @Override
    public void create() {
        System.out.println("audi chassis ...");
    }
}

// 起亚汽车底盘
public class KIAChassis implements IChassis {
    @Override
    public void create() {
        System.out.println("KIA chassis ...");
    }
}

引擎:

// 抽象出引擎接口
public interface IEngine {
    void create();
}

// 奥迪发动机
public class AudiEngine implements IEngine {
    @Override
    public void create() {
        System.out.println("audi engine ...");
    }
}

// 起亚发动机
public class KIAEngine implements IEngine {
    @Override
    public void create() {
        System.out.println("KIA engine ...");
    }
}

底盘工厂:

public class ChassisFactory {
    public static IChassis createChassis(Class<? extends IChassis> clazz) {
        try {
            if (null != clazz) {
                return clazz.newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

引擎工厂:

public class EngineFactory {
    public static IEngine createEngine(Class<? extends IEngine> clazz) {
        try {
            if (null != clazz) {
                return clazz.newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

汽车工厂:

public class CarFactory {
    public IChassis chassis;
    public IEngine engine;

    void createCar(Class<? extends IChassis> chassis, Class<? extends IEngine> engine) {
        this.chassis = ChassisFactory.createChassis(chassis);
        this.engine = EngineFactory.createEngine(engine);
    }
}

客户:

public class Client {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory();
        carFactory.createCar(AudiChassis.class, AudiEngine.class);
        carFactory.chassis.create();
        carFactory.engine.create();
        carFactory.createCar(KIAChassis.class, KIAEngine.class);
        carFactory.chassis.create();
        carFactory.engine.create();
    }
}

运行结果:
在这里插入图片描述

可以看到,客户只需要传入需求,工厂就会根据客户的需求生产产品,客户无需知道具体的实现过程,这使用户与产品实现了一定程度的解耦(但产品与工厂耦合了)。

但问题也是显而易见的。例如用户传入一个Audi的底盘和一个KIA的引擎,工厂并不会理会,而会按照用户的选择,生产出一部古怪的汽车(或是这两个零件无法组合在一起)。在某些情况下,这种情况是不应该出现或者不允许的,怎么解决呢?这里引入抽象工厂模式。

抽象工厂模式

定义:
场景:
优点:
缺点:

产品族: 同一个品牌,比如:海尔、美的。
产品等级: 同一个产品,比如:冰箱、洗衣机。

抽象工厂模式与工厂方法模式的最大区别就在于:工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。
关于产品等级和产品族的概念,见下图:
在这里插入图片描述

对于工厂方法模式,每个工厂负责一个产品等级,各自生产零件,最后由总工厂组合成产品。而抽象工厂模式,则是一个总工厂负责统筹,总工厂下面的子工厂各自负责一个品族,生成产品,最后由是由总工厂将产品交付给客户。

案例代码实现:
底盘和引擎的实现和上面的工厂方法模式一样。
下面创建一个抽象工厂、Audi工厂和KIA工厂:

// 抽象一个工厂架构
public interface AbstractFactory {
    Chassis createChassis();
    Engine createEngine();
}

// 实现一个具体的工厂,这个工厂专门生产奥迪汽车
public class AudiFactory implements AbstractFactory {
    @Override
    public Chassis createChassis() {
        return new AudiChassis();
    }

    @Override
    public Engine createEngine() {
        return new AudiEngine();
    }
}

// 这个工厂专门生产起亚汽车
public class KIAFactory implements AbstractFactory{
    @Override
    public Chassis createChassis() {
        return new KIAChassis();
    }

    @Override
    public Engine createEngine() {
        return new KIAEngine();
    }
}

汽车工厂:

public class CarFactory {
    private Chassis chassis;
    private Engine engine;

    // 这里直接传入对应产品族的工厂实例,杜绝了产品等级不一致的问题
    public void createCar(AbstractFactory factory){
        this.chassis = factory.createChassis();
        this.engine = factory.createEngine();
        System.out.println("A car is created.");
        System.out.printf("CHASSIS: %s\n", chassis.identify());
        System.out.printf("ENGINE: %s", engine.identify());
    }
}

客户,生产一部起亚汽车:

public class Client {
    // 下一个汽车订单
    public void orderACar(AbstractFactory factory){
        CarFactory cf = new CarFactory();
        cf.createCar(factory);
    }
}
// 测试类
public class ClientTest {
    public static void main(String[] args) throws Exception{
        Client client = new Client();
        // 传入一个具体的工厂,就能生产出对应的汽车
        client.orderACar(new KIAFactory());
    }
}

可以看到,客户使用抽象工厂来创建需要的对象,客户只是面向产品的接口编程,根本无需知道工厂的具体实现。也就是说,客户端从具体的产品实现中解耦。而且,由于具体工厂限制了产品族对中每个零件的产品等级,从而解决了上面产品等级不对应的问题,不会再出现Audi底盘装载KIA引擎的车了。

另外,抽象工厂模式实现了产品与工厂的解耦,所以支持增加产品族。例如我们要增加一个BMW车的产品族,只需增加一个BMW工厂实例,和对应的零件实例就可以了,也就是说,我们可以通过实现AbstractFactoryChassisEngine这几个接口就可以增加一个产品族。但如果想要增加产品等级,则需要修改工厂的具体实现。

总结

使用工厂模式就是提醒我们,写代码的时候,尽可能的避免使用new关键字创建对象,因为new关键字意味着依赖,如果一个类到处都是使用new关键字实例化,那么哪天这个类不用了,要换成其它的实现类,我们就需要到处修改,这样就太消耗时间了。

比如上面的工厂方法案例,现在已经研发出了第二代奥迪底盘,只需要创建一个第二代奥迪底盘的实现类,然后在底盘工厂替换下实现类,就可实现生产第二代底盘的奥迪汽车了。代码如下:

public class AudiChassis2 implements Chassis{
    @Override
    public String identify() {
        return "this is a Chassis of Audi2.";
    }
}

public class ChassisFactory {
    // 生成底盘的方法,根据传入的类型生产对应类型的底盘
    public static Chassis createChassis(String chassisType) {
        Chassis chassis;
        switch (chassisType) {
            case "Audi": chassis = new AudiChassis2(); break;
            case "KIA": chassis = new KIAChassis(); break;
            default: chassis = null;
        }
        return chassis;
    }
}

总之,工厂模式就是提醒我们,当需要实例化对象时,我们尽可能避免使用new去实例化,考虑为对象创建一个统一的来源。

产品族:同一个品牌,比如:海尔、美的。
产品等级:同一个产品,比如:冰箱、洗衣机。

具体的美的工厂。
具体的海尔工厂。

抽象工厂太复杂了,所以用的不多,最常用简单工厂和工厂方法。

简单工厂:一个工厂可以创建很多不同类型的产品。
工厂方法:一类产品(比如:冰箱)对应一个工厂。
抽象工厂:产品族(品牌)对应一个抽象工厂,然后一个具体的产品品牌(美的)实现抽象工厂。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值