设计模式介绍和实现:工厂方法模式(Factory Method Pattern)

一、概念介绍

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种将对象创建的过程延迟到子类中进行的方法。这种模式通过定义一个创建对象的接口,但将具体的实现延迟到子类来完成,从而使得一个类在实例化时可以通过其子类来决定实例化哪个类。这样可以提高代码的灵活性和可扩展性。

工厂方法模式包含以下几个角色:
抽象产品(Abstract Product):定义了工厂方法模式所创建的对象的接口,通常是一个抽象类或接口。
具体产品(Concrete Product):实现了抽象产品接口,是工厂方法模式所创建的对象的具体实现类。
抽象工厂(Abstract Factory):定义了一个创建产品的工厂方法接口,通常是一个抽象类或接口。这个接口中通常会包含一个或多个工厂方法,用于创建具体产品的实例。
具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体产品的实例。

优点:
松耦合性:工厂方法模式将客户端与具体产品的实现分离,客户端只需知道产品的抽象类型,无需关心具体的实现细节,从而降低了客户端和具体产品之间的耦合性。
可扩展性:通过添加新的具体工厂和具体产品类,可以很方便地扩展系统的功能,而无需修改现有的代码。
符合开闭原则:对扩展开放、对修改关闭。增加新的产品类时,无需修改已有代码,只需添加新的具体产品类和具体工厂类即可。

缺点:
类的个数增加:引入了多个工厂类和产品类,使得系统中的类的数量增加,增加了代码的复杂度和维护成本。
增加了系统的抽象性和理解难度:工厂方法模式引入了更多的抽象层次,使得系统更加灵活,但也增加了理解和学习的难度。
工厂方法模式适用于以下情况:

当一个类不知道它所需要的对象的类时。
当一个类希望由它的子类来指定它所创建的对象时。
当类将创建对象的职责委托给多个帮助子类中的其中一个,并且想让子类中的某一个类来实例化这个类时。

二、实现方法(爷爷奶奶都看得懂~)

将以手机组装为例讲解工厂模式。中国的手机最具有性价比的手机是小米手机,美国最具性价比的手机是苹果手机,同一个工厂怎么生产小米手机和苹果手机呢?

1、简单工厂模式

生产前先出设计图,整体类图如下:
在这里插入图片描述

定义手机基类:

package designPattern.build.factory.simpleFactory.abstractProductClass;
/**
* 手机基类
*/
public abstract class BasicPhone {
    /**价格级别*/
    private String priceLevel;
    /**品牌*/
    private String brand;
	/**手机会响铃*/
    abstract String ring();
	/**手机可以设置语言*/
    abstract String language();
	/**下面的getter和setter方法省略,要本地运行必须补充完整getter和setter方法*/
}

定义美国苹果手机(继承了手机基类):

package designPattern.build.factory.simpleFactory.abstractProductClass;

public class AmericanPhone extends BasicPhone {

    public AmericanPhone() {
        this.setPriceLevel("normal");
        this.setBrand("Apple");
    }

    @Override
    public String ring() {
        return "DiDiDi";
    }

    @Override
    public String language() {
        return "English";
    }
}

再定义中国小米手机(继承了手机基类):

package designPattern.build.factory.simpleFactory.abstractProductClass;

public class ChinesePhone extends BasicPhone {

    public ChinesePhone() {
        this.setPriceLevel("普通");
        this.setBrand("小米");
    }

    @Override
    public String ring() {
        return "DuDuDu";
    }

    @Override
    public String language() {
        return "中文";
    }
}

有了苹果手机和小米手机后,怎么用一个工厂生产出来呢?直接让一个工厂生产指定的手机即可,这个工厂只生产畅销手机,当销售地区为中国时就生产小米手机,当销售地区为美国时就生产苹果手机,
简单工厂如下:

package designPattern.build.factory.simpleFactory.abstractProductClass;

public class PhoneCreator {
    public static BasicPhone producePhone(String nation) {
        if ("中国".equals(nation)) {
            return new ChinesePhone();
        }
        if ("美国".equals(nation)) {
            return new AmericanPhone();
        }
        return null;
    }
}

测试代码如下:

package designPattern.build.factory.simpleFactory.abstractProductClass;

/**
 * 简单工厂模式
 */
public class Test {
    public static void main(String[] args) {
    	// 生产一台中国销售的手机(小米手机)
        BasicPhone phone1 = PhoneCreator.producePhone("中国");
        // 生产一台美国销售的手机(苹果手机)
        BasicPhone phone2 = PhoneCreator.producePhone("美国");
        System.out.println("phone1的语言为:" + phone1.language() + ",响铃声音为:" + phone1.ring());
        System.out.println("phone2的语言为:" + phone2.language() + ",响铃声音为:" + phone2.ring());
    }
}
/**
输出如下:
phone1的语言为:中文,响铃声音为:DuDuDu
phone2的语言为:English,响铃声音为:DiDiDi
*/

观察以上的案例,如果后面要增加新手机型号生产,譬如要生产华为手机,需要修改PhoneCreator 的代码,很显然违背了对拓展开放,对修改关闭的原则。那要怎么办?
可以这样来,把生产手机的工厂抽象化,定义一种专门生产手机的基础工厂,各个地方要生产什么牌子的手机都行,只要继承基础工厂、然后进行具体实现即可!
下面的就是把工厂抽象一层的正常工厂模式。

2、普通工厂模式

我们的任务还是生产中国手机和美国手机。
设计前,先把设计类图整理好:
在这里插入图片描述

先定义手机基类:

package designPattern.build.factory.normalFactory;

/**
 * 手机基类
 */
public abstract class BasicPhone {
    /**价格等级*/
    private String priceLevel;
    /**品牌*/
    private String brand;
    /**销售地区*/
    private String salesNation;

    abstract String ring();

    abstract String language();

    public BasicPhone(String priceLevel, String brand, String salesNation) {
        this.priceLevel = priceLevel;
        this.brand = brand;
        this.salesNation = salesNation;
    }
/**下面的getter和setter方法省略,要本地运行必须补充完整getter和setter方法*/
}

美国手机:

package designPattern.build.factory.normalFactory;

/**
 * 美国手机
 */
public class AmericanPhone extends BasicPhone {

    public AmericanPhone(String priceLevel, String brand, String salesNation) {
        super(priceLevel, brand, salesNation);
    }

    @Override
    public String ring() {
        return "DiDiDi";
    }

    @Override
    public String language() {
        return "English";
    }
}

中国手机:

package designPattern.build.factory.normalFactory;

/**
 * 中国手机
 */
public class ChinesePhone extends BasicPhone {

    public ChinesePhone(String priceLevel, String brand, String produceDistrict) {
        super(priceLevel, brand, produceDistrict);
    }
    
    @Override
    public String ring() {
        return "DuDuDu";
    }

    @Override
    public String language() {
        return "中文";
    }
}

下面开始建工厂,首先定义手机工厂基类:

package designPattern.build.factory.normalFactory;
/**
 * 抽象手机工厂
 * 定义了生产手机的方法,可以看成只生产了无牌手机,具体贴啥牌可以由子工厂确定
 * */
public interface BasicPhoneCreator {
    BasicPhone producePhone(String salesNation);
}

再定义专门生产中国手机的工厂,只生产小米手机,实现了手机工厂基类:
注意,工厂模式下,每个具体工厂只能生产一种产品!

package designPattern.build.factory.normalFactory;

/**
 * 中国手机生产厂:生产小米手机
 */
public class ChinaPhoneFactory implements BasicPhoneCreator {
    @Override
    public BasicPhone producePhone(String salesNation) {
        return new ChinesePhone("低价", "小米", salesNation);
    }
}

再定义美国手机生产厂,也实现了手机工厂基类:
注意,工厂模式下,每个具体工厂只能生产一种产品!

package designPattern.build.factory.normalFactory;

/**
 * 美国手机生产厂:生产苹果手机
 */
public class AmericaPhoneFactory implements BasicPhoneCreator {
    @Override
    public BasicPhone producePhone(String salesNation) {
        return new AmericanPhone("高价", "苹果", salesNation);
    }
}

开始生产工作(测试代码):

package designPattern.build.factory.normalFactory;

/**
 * 普通工厂模式
 */
public class Test {
    public static void main(String[] args) {
        // 中国有制造业优势,同样的造手机,中国价格更低
        BasicPhoneCreator chinaFactory = new ChinaPhoneFactory();
        BasicPhone phone1 = chinaFactory.producePhone("中国市场");
        BasicPhone phone2 = chinaFactory.producePhone("美国市场");

        BasicPhoneCreator americaFactory = new AmericaPhoneFactory();
        BasicPhone phone3 = americaFactory.producePhone("中国市场");
        BasicPhone phone4 = americaFactory.producePhone("美国市场");

        System.out.println("中国工厂生产的phone1的销售市场为:" + phone1.getSalesNation() + ",默认品牌为:" + phone1.getBrand() + ",价格级别为:" + phone1.getPriceLevel());
        System.out.println("中国工厂生产的phone2的销售市场为:" + phone2.getSalesNation() + ",默认品牌为:" + phone2.getBrand() + ",价格级别为:" + phone2.getPriceLevel());

        System.out.println("美国工厂生产的phone3的销售市场为:" + phone3.getSalesNation() + ",默认品牌为:" + phone3.getBrand() + ",价格级别为:" + phone3.getPriceLevel());
        System.out.println("美国工厂生产的phone4的销售市场为:" + phone4.getSalesNation() + ",默认品牌为:" + phone4.getBrand() + ",价格级别为:" + phone4.getPriceLevel());

    }
}

/**
输出如下:
中国工厂生产的phone1的销售市场为:中国市场,默认品牌为:小米,价格级别为:低价
中国工厂生产的phone2的销售市场为:美国市场,默认品牌为:小米,价格级别为:低价
美国工厂生产的phone3的销售市场为:中国市场,默认品牌为:苹果,价格级别为:高价
美国工厂生产的phone4的销售市场为:美国市场,默认品牌为:苹果,价格级别为:高价
*/

通过以上案例我们发现,普通工厂只能生产一种牌子的手机,但是我们还想让工厂生产同一个牌子的其他周边物件就不行了,譬如专门生产苹果手机的工厂,我们还想让它同时生产苹果耳机;生产中国小米手机的工厂,我们还想让同时生成小米耳机。普通工厂实现不了,那怎么办?

我们只需要在工厂基类中增加方法即可!先前只能生产手机、现在加上周边设备的生产方法,如下:

3、抽象工厂模式

我们现在要求工厂不仅能生产手机、还要能生产同品牌的耳机。
开工前先画出设计类图:
在这里插入图片描述

先定义手机和耳机的类:
手机基类:

package designPattern.build.factory.abstractFactory;
/**
 * 手机基类
 * */
public abstract class BasicPhone {
    /**价格等级*/
    private String priceLevel;
    /**品牌*/
    private String brand;
    /**销售国家*/
    private String salesNation;

    abstract String ring();

    abstract String language();

    public BasicPhone(String priceLevel, String brand, String salesNation) {
        this.priceLevel = priceLevel;
        this.brand = brand;
        this.salesNation = salesNation;
    }
    /**下面的getter和setter方法省略,要本地运行必须补充完整getter和setter方法*/
}

中国手机(继承了手机基类):

package designPattern.build.factory.abstractFactory;

public class ChinesePhone extends BasicPhone {

    public ChinesePhone(String priceLevel, String brand, String produceDistrict) {
        super(priceLevel, brand, produceDistrict);
    }
    @Override
    public String ring() {
        return "DuDuDu";
    }

    @Override
    public String language() {
        return "中文";
    }
}

美国手机(继承了手机基类):

package designPattern.build.factory.abstractFactory;

public class AmericanPhone extends BasicPhone {

    public AmericanPhone(String priceLevel, String brand, String salesNation) {
        super(priceLevel, brand, salesNation);
    }

    @Override
    public String ring() {
        return "DiDiDi";
    }

    @Override
    public String language() {
        return "English";
    }
}

耳机基类:

package designPattern.build.factory.abstractFactory;
/**
 * 耳机基类
 * */
public abstract class BasicEarpieces {
    /**价格级别*/
    private String priceLevel;
    /**品牌*/
    private String brand;
    /**销售国家*/
    private String salesNation;

    /**播放音乐的功能*/
    abstract String playMusic();


    public BasicEarpieces(String priceLevel, String brand, String salesNation) {
        this.priceLevel = priceLevel;
        this.brand = brand;
        this.salesNation = salesNation;
    }
  /**下面的getter和setter方法省略,要本地运行必须补充完整getter和setter方法*/
}

中国耳机(继承了耳机基类):

package designPattern.build.factory.abstractFactory;

public class ChineseEarPieces extends BasicEarpieces {


    public ChineseEarPieces(String priceLevel, String brand, String salesNation) {
        super(priceLevel, brand, salesNation);
    }

    @Override
    String playMusic() {
        return "正在播放王菲的传奇:~~~~~~~~~~~~~~~~~~~~";
    }
}

美国耳机(继承了耳机基类):

package designPattern.build.factory.abstractFactory;

public class AmericanEarPieces extends BasicEarpieces {


    public AmericanEarPieces(String priceLevel, String brand, String salesNation) {
        super(priceLevel, brand, salesNation);
    }

    @Override
    String playMusic() {
        return "正在播放Lady GaGa的BadRomance:~~~~~~~~~~~~~~~~~~~~";
    }
}

重头戏来了,下面开始建厂,首先是工厂基类:

package designPattern.build.factory.abstractFactory;
/**
 * 生产手机和手机周边设备的抽象工厂
 * */
public interface BasicPhoneCreator {
    /**生产手机*/
    BasicPhone producePhone(String salesNation);

    /**生产耳机*/
    BasicEarpieces produceEarpieces(String salesNation);
}

中国手机工厂(实现了抽象工厂):生产小米手机、小米耳机,价格很实惠

package designPattern.build.factory.abstractFactory;

public class ChinesePhoneFactory implements BasicPhoneCreator {
    @Override
    public BasicPhone producePhone(String salesNation) {
        return new ChinesePhone("3000元以内", "小米", salesNation);
    }

    @Override
    public BasicEarpieces produceEarpieces(String salesNation) {
        return new ChineseEarPieces("500元以内", "小米", salesNation);
    }
}

美国手机工厂(实现了抽象工厂):生产苹果手机、苹果耳机,价格很昂贵

package designPattern.build.factory.abstractFactory;

public class AmericanPhoneFactory implements BasicPhoneCreator {
    @Override
    public BasicPhone producePhone(String salesNation) {
        return new AmericanPhone("8000元以上", "苹果", salesNation);
    }

    @Override
    public BasicEarpieces produceEarpieces(String salesNation) {
        return new AmericanEarPieces("2000元内", "苹果", salesNation);
    }
}

产品已经定义好、工厂也建立好,下面开始生产(测试代码):

package designPattern.build.factory.abstractFactory;

/**
 * 抽象工厂模式
 */
public class Test {
    public static void main(String[] args) {
        // 中国有制造业优势,同样的造手机,中国价格更低
        /**
         * AmericaPhoneFactory和ChinaPhoneFactory中的producePhone方法的实现似乎混淆了工厂方法模式的意图。通常,一个工厂类负责生产一种产品。
         * 但在你的案例中,每个工厂似乎都能生产多种产品。这种实现更接近于简单工厂模式,而不是工厂方法模式。
         * 工厂方法模式的关键在于有多个工厂类,每个工厂类负责创建一种具体的产品。但在你的逻辑中,一个工厂能够创建不同的产品,这与工厂方法模式的定义稍有出入。
         * 总结
         * 虽然你的实现基本遵循了工厂方法模式的构思,但对于工厂类的设计应该有更明确的职责划分,即一个工厂类负责创建一种类型的产品。你可能需要重新审视
         * 每个工厂类的职责,确保它们遵守工厂方法模式的原则。
         * */
        // 生产手机
        BasicPhoneCreator chinaFactory = new ChinesePhoneFactory();
        BasicPhone phone1 = chinaFactory.producePhone("中国市场");
        BasicPhone phone2 = chinaFactory.producePhone("美国市场");

        BasicPhoneCreator americaFactory = new AmericanPhoneFactory();
        BasicPhone phone3 = americaFactory.producePhone("中国市场");
        BasicPhone phone4 = americaFactory.producePhone("美国市场");

        System.out.println("中国工厂生产的手机phone1的销售市场为:" + phone1.getSalesNation() + ",默认品牌为:" + phone1.getBrand() + ",价格级别为:" + phone1.getPriceLevel());
        System.out.println("中国工厂生产的手机phone2的销售市场为:" + phone2.getSalesNation() + ",默认品牌为:" + phone2.getBrand() + ",价格级别为:" + phone2.getPriceLevel());
        System.out.println("美国工厂生产的手机phone3的销售市场为:" + phone3.getSalesNation() + ",默认品牌为:" + phone3.getBrand() + ",价格级别为:" + phone3.getPriceLevel());
        System.out.println("美国工厂生产的手机phone4的销售市场为:" + phone4.getSalesNation() + ",默认品牌为:" + phone4.getBrand() + ",价格级别为:" + phone4.getPriceLevel());

        // 生产耳机
        BasicEarpieces earpieces1 = chinaFactory.produceEarpieces("中国市场");
        BasicEarpieces earpieces2 = chinaFactory.produceEarpieces("美国市场");

        BasicEarpieces earpieces3 = americaFactory.produceEarpieces("中国市场");
        BasicEarpieces earpieces4 = americaFactory.produceEarpieces("美国市场");

        System.out.println("中国工厂生产的耳机earpieces1的销售市场为:" + earpieces1.getSalesNation() + ",默认品牌为:" + earpieces1.getBrand() + ",价格级别为:" + earpieces1.getPriceLevel());
        System.out.println("中国工厂生产的耳机earpieces2的销售市场为:" + earpieces2.getSalesNation() + ",默认品牌为:" + earpieces2.getBrand() + ",价格级别为:" + earpieces2.getPriceLevel());
        System.out.println("美国工厂生产的耳机earpieces3的销售市场为:" + earpieces3.getSalesNation() + ",默认品牌为:" + earpieces3.getBrand() + ",价格级别为:" + earpieces3.getPriceLevel());
        System.out.println("美国工厂生产的耳机earpieces4的销售市场为:" + earpieces4.getSalesNation() + ",默认品牌为:" + earpieces4.getBrand() + ",价格级别为:" + earpieces4.getPriceLevel());
    }
}

/**
输出如下:
中国工厂生产的手机phone1的销售市场为:中国市场,默认品牌为:小米,价格级别为:3000元以内
中国工厂生产的手机phone2的销售市场为:美国市场,默认品牌为:小米,价格级别为:3000元以内
美国工厂生产的手机phone3的销售市场为:中国市场,默认品牌为:苹果,价格级别为:8000元以上
美国工厂生产的手机phone4的销售市场为:美国市场,默认品牌为:苹果,价格级别为:8000元以上


中国工厂生产的耳机earpieces1的销售市场为:中国市场,默认品牌为:小米,价格级别为:500元以内
中国工厂生产的耳机earpieces2的销售市场为:美国市场,默认品牌为:小米,价格级别为:500元以内
美国工厂生产的耳机earpieces3的销售市场为:中国市场,默认品牌为:苹果,价格级别为:2000元内
美国工厂生产的耳机earpieces4的销售市场为:美国市场,默认品牌为:苹果,价格级别为:2000元内

*/

三、总结

模式特点优点缺点
简单工厂模式(Simple Factory Pattern)工厂类负责创建所有对象的实例,客户端通过传递参数来获取对象1. 客户端代码与实际创建对象的代码解耦
2. 简单易用
1. 工厂类承担所有对象创建职责,违背单一职责原则
2. 增加新产品时需要修改工厂类,违反开闭原则
普通工厂模式(Factory Method Pattern)定义创建对象的接口,由子类决定实例化哪一个类1. 遵循开闭原则,增加新产品时只需增加相应的子类
2. 客户端代码与具体产品实现解耦
1. 增加系统复杂性,可能导致类数量增加
抽象工厂模式(Abstract Factory Pattern)提供一个创建相关或依赖对象家族的接口,无需指定具体的类1. 易于交换产品系列,修改具体工厂类只需在一个地方进行
2. 保证客户端始终使用同一个产品系列
1. 增加系统的抽象层次和复杂性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值