简单工厂模式
产品种类较少时使用。只需一个工厂完成产品的创建,耦合度较高,同时较为简单,只需对产品进行抽象
/**
* 产品抽象
*/
public interface GameControllers{
void publish();
}
两个具体的产品
public class Product_ones implements GameControllers {
@Override
public void publish() {
System.out.println("XboxOnes手柄于2015年发布");
}
}
public class Product_Series implements GameControllers {
@Override
public void publish() {
System.out.println("XboxSeries手柄2020年发布");
}
}
最后一个工厂类
public final class GCFactory {
public static GameControllers makeProduct(int year){
switch (year){
case 2015:
return new Product_ones();
case 2020:
return new Product_Series();
default:
System.out.println("???");
return null;
}
}
}
使用时调用工厂类的makeProduct方法,并传入参数,得到具体的产品
GameControllers controllerXb1 = GCFactory.makeProduct(2015);
GameControllers controllerXb2 = GCFactory.makeProduct(2020);
总结:简单工厂模式结构简单,但耦合度高,当添加新的产品时需要进入工厂内部进行修改代码(增加一个case),违背了开闭原则
开闭原则的核心思想:
1、对扩展开放:当需要添加新的功能或修改现有功能的行为时,应当能够通过增加新代码的方式来完成,而不是修改已有的、经过验证的代码。
2、对修改关闭:一旦某个部分的代码完成并经过测试,就不应该因为新需求而频繁地去改动它,以减少引入错误的风险,并保持系统的稳定性。
工厂方法模式
简单工厂模式违背了开闭原则,而工厂方法模式在简单工厂模式的基础上又进行了抽象,使其可以在不修改原来代码的情况下引入新产品,即满足开闭原则
上文中的简单工厂模式中我们只对产品进行了抽象,在此基础上,工厂方法模式又对工厂进行了抽象
首先,产品的抽象和上文相同,定义一个表示手机的抽象产品接口,该接口声明了所有手机都应具备的基本行为或属性
/**
* 产品的抽象
*/
public interface IPhone {
String getModel();
String getBrand();
void call(String phoneNumber);
void sendMessage(String message, String recipient);
}
两个具体的产品(华为手机和小米手机)
public class HuaweiPhone implements IPhone {
// 实现接口方法
}
public class XiaomiPhone implements IPhone {
// 实现接口方法
}
// 可以继续为其他品牌如Apple、Samsung等创建相应类
新增工厂的抽象
/**
* 手机工厂的抽象
*/
public interface IPhoneFactory {
IPhone createPhone();
}
两个具体的工厂,生产具体的产品
public class HuaweiFactory implements IPhoneFactory {
@Override
public IPhone createPhone() {
return new HuaweiPhone();
}
}
public class XiaomiFactory implements IPhoneFactory {
@Override
public IPhone createPhone() {
return new XiaomiPhone();
}
}
同样,调用时依然调用工厂(使用工厂方法来创建不同品牌的手机,而无需关心手机的具体创建过程)
//调用,得到具体的工厂
IPhoneFactory huaweiFactory = new HuaweiFactory();
//工厂生产具体的产品
IPhone huaweiPhone = huaweiFactory.createPhone();
huaweiPhone.call("1234567890");
通过这样的设计,当需要增加新的手机品牌时,只需添加新的具体产品类和对应的工厂类,而不需要修改现有的工厂类或客户端代码,符合开闭原则。
一个品牌应该不只有手机一种生产线,也可能会有笔记本电脑、汽车、电视等。而且一种产品也会推陈出新,发布多种机型,仔细想想,在不违背开闭原则的基础上似乎不能用工厂方法模式来解决,这时需要使用抽象工厂模式来解决
抽象工厂模式
假设小米和华为不仅生产手机,还进入了智能汽车行业,每家公司都有一套自己的设计理念和产品线。
既然新增了汽车这一产品,那就需要新增一个抽象的汽车类,定义了汽车的基本操作,如启动、停车、行驶等
public interface Car {
}
具体产品:
小米的 XiaomiPhone 和 XiaomiCar 类,实现了上述抽象产品接口。
华为的 HuaweiPhone 和 HuaweiCar 类,同样实现了这些接口。
抽象工厂:
AbstractProductFactory 接口,声明了创建智能手机和电动汽车的方法,如 createSmartphone() 和 createElectricCar()。
public interface AbstractProductFactory{
IPhone createPhone();
Car createCar()
}
具体工厂:
XiaomiFactory 类,实现了 AbstractProductFactory 接口,用来生产小米品牌的智能手机和电动汽车。
HuaweiFactory 类,实现了相同接口,生产华为品牌的相应产品。
为什么说抽象工厂模式复合开闭原则,请看具体场景示例
应用场景示例
假定小米和华为需要为不同市场区域定制产品特性,抽象工厂模式可以帮助它们灵活地调整生产线,同时保持代码的结构清晰和低耦合。
小米应用示例:
当小米想要推出面向年轻人的科技感十足的智能手机和搭配的智能汽车时,可以通过创建一个 XiaomiYouthFactory(具体的工厂类),这个新工厂类里面的createPhone()和createCar() 会返回新推出的产品
↓↓↓↓
XiaomiPhoneYouth (具体的手机产品,实现IPhone接口)和 XiaomiCarYouth(同理)
新建一个工厂类
public class XiaomiYouthFactory implements AbstractProductFactory{
@Override
public IPhone createPhone() {
return new XiaomiPhoneYouth();
}
@Override
public Car createCar() {
return new XiaomiCarYouth();
}
}
抽象工厂模式和工厂方法模式
上述例子中,如果去掉手机或者汽车,那么抽象工厂模式就会退化为工厂模式
当去掉其中一种产品等级结构,比如只剩下手机这一种产品等级结构,而不同品牌仍然需要生产自己的手机型号,这时抽象工厂模式的“多产品等级结构”特性就失去了意义。因为现在只需要创建不同品牌的一个产品(手机),不再需要处理多个产品等级结构之间的关系,这样的设计就更接近于工厂方法模式,而非抽象工厂模式。工厂方法模式专注于为一个产品等级结构内的产品创建实例,而不需要考虑跨等级结构的协调。
所以,如果从系统中移除了汽车这一整个产品等级结构,只剩下手机产品线,并且每个工厂只负责创建手机这一类产品,那么原本的抽象工厂模式确实可能退化为工厂方法模式,因为不再需要处理多个不同的产品等级结构。
总结
如果侧重于生产不同品牌的一种产品时,采用工厂模式最合适
如果侧重于生产不同品牌的多种产品时,采用抽象工厂模式会更加合适。