工厂模式(简单工厂、工厂方法和抽象工厂)

工厂模式

学习工厂模式必须知道的概念:

  1. 产品
  2. 抽象产品
    抽象类和接口
  3. 产品簇
    多个内在联系或者有逻辑关系的产品
    比如三秦套餐中:凉皮+冰峰+肉夹馍
  4. 产品等级

产品等级和产品簇的关系:
在这里插入图片描述

我们平时创建对象的方式:

//抽象产品
interface Foot {
    void eat();
}
//具体产品(汉堡包
class Hamburger implements com.shi.design.simple_factory.Foot {

    @Override
    public void eat() {
        System.out.println("在吃汉堡包!");
    }
}
//上面代码为服务端,下面为客户端,我们身份为客户身份,不能修改服务端代码
//=============================================
public class Test {

    public static void main(String[] args) {
        Foot f = new Hamburger();
        f.eat();
    }
}

上面的这种设计十分脆弱,因为只要服务端修改了代码,客户端也必须跟着修改,这样的设计,服务端和客户端是耦合的。我们需要的是,无论服务端怎么修改,我们客户端的代码是不需要改变的。

简单工厂模式

针对上面的问题,我们采用简单工厂模式进行修改

//抽象产品
interface Foot {
    void eat();
}

//具体产品(汉堡包
class Hamburger implements Foot {

    @Override
    public void eat() {
        System.out.println("在吃汉堡包!");
    }
}

//具体产品(米线
class RiceNoodle implements Foot {

    @Override
    public void eat() {
        System.out.println("在吃米线!");
    }
}

//简单工厂类
class FootFactory {
    public static Foot getFoot(int type) {
        Foot foot = null;
        switch (type) {
            case 1:
                foot = new Hamburger();
                break;
            case 2:
                foot = new RiceNoodle();
                break;
        }
        return foot;
    }
}

//时光线----上面为很久以前的代码,我们不能修改,下面为现在我们书写的代码
//==================================================
//
public class AppTest {

    public static void main(String[] args) {
        Foot foot = FootFactory.getFoot(1);
        foot.eat();
    }
}

简单工厂的优点:

  1. 将具体产品的类型从客户端中解耦出来
  2. 服务器端如果修改了具体产品的类名,客户端也不知道
  3. 这复合了面向接口编程的思想

缺点:

  1. 客户端不得不死记硬背那些常量与具体产品的映射关系
  2. 如果具体产品特别多,那么简单工厂就会别的特别臃肿,比如如果有一百个具体产品,那么就得有100个case
  3. 如果变化来了,客户端需要新添加方法,那么就得修改简单工厂中的内容,不符合开闭原则

简单工厂的UML类图
简单工厂的UML类图

工厂方法模式

针对于简单工厂产生的问题,我们使用工厂方法模式

interface Foot {
    void eat();
}

//具体产品(汉堡包
class Hamburger2 implements Foot {

    @Override
    public void eat() {
        System.out.println("在吃汉堡包!");
    }
}

//具体产品(米线
class RiceNoodle implements Foot {

    @Override
    public void eat() {
        System.out.println("在吃米线!");
    }
}

//设置工厂接口
interface FootFactory {
    Foot getFoot();
}

//汉堡包工厂
class HambergerFactory implements FootFactory {

    @Override
    public Foot getFoot() {
        return new Hamburger2();
    }
}

//米线接口
class RiceNoodleFactory implements FootFactory {

    @Override
    public Foot getFoot() {
        return new RiceNoodle();
    }
}

class Product {
    public static void Evaluate(FootFactory footFactory){
        Foot foot = footFactory.getFoot();
        System.out.println("评委A开始品尝");
        foot.eat();

        Foot foot1 = footFactory.getFoot();
        System.out.println("评委B开始品尝");
        foot1.eat();

        Foot foot2 = footFactory.getFoot();
        System.out.println("评委C开始品尝");
        foot2.eat();
    }
}

//===================================
//扩充方法
class ColdRice implements Foot {

    @Override
    public void eat() {
        System.out.println("在吃凉皮!");
    }
}

//凉皮创建工厂
class ColdRiceFactory implements FootFactory {

    @Override
    public Foot getFoot() {
        return new ColdRice();
    }
}

public class AppTest {

    public static void main(String[] args) {
        HambergerFactory hambergerFactory = new HambergerFactory();
        Foot foot = hambergerFactory.getFoot();
        foot.eat();

        Product.Evaluate(new HambergerFactory());
    }
}

优点:

  1. 仍然具有简单工厂的优点,服务器端修改了具体的产品的类名以后,客户端不知道
  2. 当客户端需要新添加一个新的产品时,不需要修改作者原来的代码,只需要扩展一个新的工厂

杆点:

  1. 我们都知道,简单工厂也好,工厂方法也好,都有一个优点,就是服务器端的具体类名修改了以后,客户端不知道!但是,反观我们现在的代码,客户端依然依赖于服务器端具体工厂的类名呀,要是服务器端的具体工厂的类名修改了,那么不是本地的调用的方法内部也得修改?
    解释: 工厂的名称,视为接口,作者有责任有义务保证工厂的名称是稳定的,也就是说,虽然客户端依赖于工厂的具体类名,可是在IT行业内,所有工厂的名字都是趋向于稳定的(并不是100%不会变),但是至少工厂类的名称,要比具体类的名字更加稳定。
  2. 既然产品是我们客户端自己扩展出来的,那么为什么不直接自己实例化呢,毕竟自己扩展出来的ColdRice这个产品,自己能够把控,为什么还要创建工厂呢?
    解释: 作者开发功能的时候,不仅仅会开发一些抽象产品,具体产品,对应的工厂,还会套配一些提前做好的架构,比如上面服务端提供的Product的品尝功能。
  3. 现在只做出ColdRiceFactory,是为了把ColdRiceFactory传入到Product.Evaluate中,所以需要需要创建这个ColdRiceFactory,那么为什么从一开始,就让Product.Evaluate接收的是Food参数呢,而不现在的FoodFactory参数?
    解释: 1)、那么在客户端传入的时候就需要传入具体类名,而不是传入工厂,那么如果传入具体类名,那么服务端具体名称修改,则我们也需要修改,2)、该业务品尝中,如果传入Foot的话,那么就是每一个评委都是吃的是同一份食物,而传入FootFactory则每一个评委在吃食物的时候就可以自己new一份食物而不是吃上一个吃剩下的。

缺点: 如果有多个产品等级,那么工厂类的数量就会爆炸式增长。

工厂方法模式的UML类图:
工厂方法模式的UML类图:

抽象工厂方法

针对工厂方法模式的缺点,我们使用抽象工厂模式。
简单来说,其实抽象工厂与工厂的区别就是将造对象的过程模拟化,比如,套餐,所有店里面都有吃和喝的,所以创建的时候就将吃和喝的放在同一个工厂里面创建,从而减少代码。

//食物接口
interface Foot {
    void eat();
}

//具体产品(汉堡包
class Hamburger implements Foot {

    @Override
    public void eat() {
        System.out.println("在吃汉堡包!");
    }
}

//具体产品(米线
class RiceNoodle implements Foot {

    @Override
    public void eat() {
        System.out.println("在吃米线!");
    }
}
//饮料接口
interface Drink {
    public void drink();
}

//抽象产品  可乐
class Cola implements Drink {

    @Override
    public void drink() {
        System.out.println("在喝可乐");
    }
}

//抽象产品  冰峰
class IcePeak implements Drink {

    @Override
    public void drink() {
        System.out.println("在喝冰峰");
    }
}

//设置工厂接口
interface Factory {
    Foot getFoot();
    Drink getDrink();
}

//肯德基(KFC)工厂
class KFCFactory implements Factory {

    @Override
    public Foot getFoot() {
        return new Hamburger();
    }

    @Override
    public Drink getDrink() {
        return new Cola();
    }
}

//三秦工厂
class SanQinFactory implements Factory {

    @Override
    public Foot getFoot() {
        return new RiceNoodle();
    }

    @Override
    public Drink getDrink() {
        return new IcePeak();
    }
}

class Product {
    public static void Evaluate(Factory footFactory){
        Foot foot = footFactory.getFoot();
        Drink drink = footFactory.getDrink();
        System.out.println("评委A开始品尝");
        foot.eat();
        drink.drink();

        Foot foot1 = footFactory.getFoot();
        Drink drink1 = footFactory.getDrink();
        System.out.println("评委B开始品尝");
        foot1.eat();
        drink1.drink();

        Foot foot2 = footFactory.getFoot();
        Drink drink2 = footFactory.getDrink();
        System.out.println("评委C开始品尝");
        foot2.eat();
        drink2.drink();
    }
}

//===================================
public class AppTest {

    public static void main(String[] args) {
        KFCFactory kfcgerFactory = new KFCFactory();
        Foot foot = kfcgerFactory.getFoot();

        foot.eat();
        Product.Evaluate(new KFCFactory());
    }
}

优点:

  1. 任然具有普通工厂和抽象工厂的优点,
  2. 更重要的是,抽象工厂吧工厂类的数量减少了,无论多少个产品等级工厂就一套。

杆点:

  1. 为啥三秦工厂的时候就是米粉加冰峰,不可以是米粉加可乐?
    解释: 抽象工厂中,可以生产多个产品, 这多个产品之间,必须都存内在联系。

缺点:

  1. 当产品等级发生变化时(添加商品等级,删除商品等级的时候),都会引起所有工厂代码的修改,就违反了开闭原则。

抽象工厂UML类图
抽象工厂UML类图
结论:当产品等级比较固定,就可以考虑使用抽象工厂,如果产品等级经常变化,则不建议使用抽象工厂。

以上内容为课后总结,如有侵权,请告知本人!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简单工厂模式是一种常见的创建型设计模式,它通过一个工厂类来创建不同类型的对象。在简单工厂模式中,客户端无需关心具体的对象创建过程,只需通过工厂类的静态方法来获取所需的对象实例。这样可以降低代码的耦合度,也方便了对象的创建和管理。 工厂方法模式是一种将对象的创建延迟到子类的设计模式。在工厂方法模式中,将对象的创建放在具体的工厂子类中,每个具体工厂子类负责创建一种类型的对象。客户端只需要和抽象工厂接口进行交互,具体的对象创建过程由具体子类来完成。这样可以提供一种扩展性更好的解决方案,对于新增产品类的扩展,只需要新增相应的具体工厂子类即可。 抽象工厂模式是一种提供一种创建一系列相关或依赖对象的接口,而无需指定具体类的设计模式。在抽象工厂模式中,通过定义抽象工厂接口和具体工厂类来创建一系列相关或依赖的对象。每个具体工厂类负责创建一组具体的对象,通过抽象工厂接口对外提供创建对象的方法。这样可以将具体对象的创建逻辑从客户端代码中分离出来,提高了系统的灵活性和可扩展性。 在Java中,你可以通过定义一个包含多个静态方法工厂类来实现简单工厂模式。每个静态方法对应一个具体的产品对象的创建逻辑。工厂方法模式可以通过定义一个抽象工厂接口和多个具体工厂类来实现。每个具体工厂类负责创建一种产品对象。抽象工厂模式可以通过定义一个抽象工厂接口和多个具体工厂类来实现。每个具体工厂类负责创建一组相关的产品对象。客户端通过访问抽象工厂接口来创建对象,具体的对象创建过程由具体工厂类来完成。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值