欢迎来到今天的学习,今天我们将一起进行工厂模式的学习。再唠叨几句,前面我有提到本月将会对java的设计模式精讲,欢迎点击头像,关注我的专栏,我会持续更新,加油!
系列文章:
话不多话,进入正题
工厂模式
我记得一本书中曾说工厂模式被分为了三种:简单工厂、工厂方法和抽象工厂,目的只有一个:”抽象“。在实际工作中,用得比较多的可能就是工厂模式、和抽象工厂模式这两类。本文将主要讲这两个、简单工厂也会说一说(比较简单)。我们采用由浅到深,由易到难的方式层层探索。
下面先看张图很易于理解。
我们要做相应的算法运算,那么定义一个抽象的运算类,定义抽象的运算方法。该工厂便搭建起来了。那工厂总得生产产品吧,那继承之接口或实现类来实现各自不同的运算法则。 这便是非常经典的工厂模式 (所有的工厂方法模式系列都逃不出这张图)
简单工厂模式
先从最简单的讲起吧。简单工厂,可不就很简单吗 哈哈。简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但好像不属于23种设计模式里。
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,也就是说定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类。
- 抽象类或接口:定义了要创建的产品对象的接口(抽象类或者接口都可以)
- 具体实现:具有统一父类的具体类型的产品(ProductA...)
- 产品工厂:负责创建产品对象。工厂模式同样体现了开闭原则,将“创建具体的产品实现类”这部分变化的代码从不变化的代码“使用产品”中分离出来,之后想要新增产品时,只需要扩展工厂的实现即可。
代码示例
我们设想这样一种场景。(做饼),有千层饼,酱香饼,还有葱花饼、鸡蛋饼......
那么我们要生产不同的饼类来满足大众的需要:
// 第一步 抽象类或接口:定义了要创建的产品对象的接口(抽象类或者接口都可以)
// 第二步 具体实现:具有统一父类的具体类型的产品(ProductA...)
// 第三步 产品工厂:负责创建产品对象。工厂模式同样体现了开闭原则,将“创建具体的产品实现类”这部分变化的代码从不变化的代码“使用产品”中分离出来,之后想要新增产品时,只需要扩展工厂的实现即可。
//定义接口()
public interface Cake {
//生产饼
void productCake();
}
//千层饼产品类
class ThousandCake implements Cake {
@Override
public void productCake() {
//...输出逻辑,千层饼的做法;
}
}
//葱花饼产品类
class ScallionCake implements Cake {
@Override
public void productCake() {
//...输出逻辑,葱花饼的做法;
}
}
//.....其他饼类省略
//第三步,创建工厂开始做饼
/**
* 饼工厂
*/
public class CakeFactory {
public Cake getInstance(int cakeType) {
if(CakeEnum.QCB.getCode() == cakeType){
//千层饼
return new ThousandCake();
} else if(CakeEnum.CHB.getCode() == cakeType){
//葱花饼
return new ScallionCake();
}
return null;
}
//调用
public static void main(String[] args) {
CakeFactory cakeFactory = new CakeFactory();
//生产出千层饼
Cake thousandCake = CakeFactory.getInstance(CakeEnum.QCB.getCode());
//...
}
}
上面的工厂实现是一个具体的类CakeFactory,而非接口或者抽象类,getInstance()方法利用if-else创建并返回具体的饼实例,如果增加新的饼子类,饼工厂的创建方法中就要增加新的if-else。如果再来酱香饼的做法该怎么办,还得写if else 这种做法扩展性差,违背了开闭原则,也影响了可读性。所以,这种方式使用在业务较简单,工厂类不会经常更改的情况。
那么针对上述情况有没有可改进的地方,往下看!
工厂方法模式
为了解决上面提到的"增加if-else"的问题,可以为每一个饼子类建立一个对应的工厂子类,这些工厂子类实现同一个抽象工厂接口。这样,创建不同种类的的饼,只需要实现不同的工厂子类。当有新种类加入时,新建具体工厂继承抽象工厂,而不用修改任何一个类。
可以看到和简单工厂相比,中间多加了为每个饼子类建立的对应的工厂类,对于根部的工厂类,这些类又叫工厂子类。
- 抽象工厂:声明了工厂方法的接口。
- 具体产品工厂:实现工厂方法的接口,负责创建产品对象。
- 产品抽象类或接口:定义工厂方法所创建的产品对象的接口。
- 具体产品实现:具有统一父类的具体类型的产品。
代码展示
// 第一步:抽象工厂:声明了工厂方法的接口。
// 第二步:具体产品工厂:实现工厂方法的接口,负责创建产品对象。
// 第三步:产品抽象类或接口:定义工厂方法所创建的产品对象的接口。
// 第四步:具体产品实现:具有统一父类的具体类型的产品。
/**
* 首先无论是做千层饼还是做葱花饼,他们都有一个加工方法,可以抽象出来
* Machine:机器
*/
public interface MachineApi {
//process:加工
//material:材料
public void process(String material);
}
//第二步:创建具体产品工厂:实现工厂方法的接口,负责创建产品对象
/**
* 千层饼机器
* thousand cake : 千层饼
*/
public class ThousandCakeMachine implements MachineApi {
@Override
public void process(String material) {
System.out.println("我把" + material + "加工成了千层饼");
}
}
/**
* 葱花饼机器
* Scallion cake : 葱花饼
*/
public class ScallionCakeMachine implements MachineApi {
@Override
public void process(String material) {
System.out.println("我把" + material + "加工成了葱花饼");
}
}
//第三步:产品抽象类或接口:定义工厂方法所创建的产品对象的接口
public abstract class Factory{
/**
* 让子类(具体工厂)来实例化具体对象(机器)
*/
public abstract MachineApi newMachine();
/**
* 加工材料
*/
public void process(String material){
MachineApi machine = newMachine();
machine.process(material);
}
}
//第四步:具有统一父类的具体类型的产品
//需要两家工厂,分别帮我生成千层饼和葱花饼
//千层饼工厂
public class ThousandCakeFactory extends Factory{
//千层饼工厂,只需要提供千层饼机器就行
@Override
public MachineApi newMachine() {
return new SteamedBunMachine();
}
}
//葱花饼工厂
public class ScallionCakeFactory extends Factory{
//葱花饼工厂,只需要提供葱花饼机器就行
@Override
public MachineApi newMachine() {
return new BoodleMachine();
}
}
ThousandCakeFactory cakeFactoryFactory = new ThousandCakeFactory ();
cakeFactoryFactory.process("面粉");//我把面粉加工成了千层饼
每一种饼种类对应一个工厂子类,在创建具体饼对象时,实例化不同的工厂子类。但是,如果业务涉及的子类越来越多,难道每一个子类都要对应一个工厂类吗?这样会使得系统中类的个数成倍增加,增加了代码的复杂度。
接着往下看,抽象工厂!
抽象工厂
可能看到这里的小伙伴会说,这博主爱吃饼吧,怎么一直说饼,哈哈,那好,这个不说饼了,说说最近比较火的我们国产品牌“李宁” and “鸿星尔克”
大家看这幅图,类似这种把产品类分组,组内不同产品由同一工厂类的不同方法实现的设计模式,就是抽象工厂模式。
抽象工厂适用于以下情况:
- 一个系统要独立于它的产品的创建、组合和表示时;
- 一个系统要由多个产品系列中的一个来配置时;
- 要强调一系列相关的产品对象的设计以便进行联合使用时;
- 当你提供一个产品类库,而只想显示它们的接口而不是实现时;
代码展示
//衣服
public interface Clothes {
void dressClothes();
}
//鸿星尔克品牌衣服
public class HXEKbrandClothes implements Clothes {
@Override
public void dressClothes() {
}
}
//李宁品牌衣服
public class LiNBrandClothes implements Clothes {
@Override
public void dressClothes() {
}
}
//鞋子
public interface Shoes {
void dressShoes();
}
//穿有鸿星尔克品牌鞋子
public class HXEKbrandShoes implements Shoes {
@Override
public void dressShoes() {
//穿着鸿星尔克牌
}
}
//穿有李宁鞋子
public class LiNBrandShoes implements Shoes {
@Override
public void dressShoes() {
//穿着李宁牌
}
}
//裤子
public interface Pants {
void dressPants();
}
//穿有鸿星尔克品牌裤子
public class HXEKbrandPants implements Pants {
@Override
public void dressPants() {
//穿着鸿星尔克牌
}
}
//穿有李宁裤子
public class LiNBrandPants implements Pants {
@Override
public void dressPants() {
//穿着李宁牌
}
}
//工厂类。工厂分为鸿星尔克工厂和李宁工厂,各自负责品牌内产品的创建
public interface IFactory {
Pants createPants();
Shoes createShoes();
Clothes createClothes();
}
//鸿星尔克
public class HXEKFactory implements IFactory {
@Override
public Pants createPants(){
Pants pants = new Pants();
//造一条裤子
return pants;
}
@Override
public Shoes createShoes(){
Shoes shoes = new Shoes();
//造一双鞋子
return shoes;
}
@Override
public Clothes createClothes(){
Clothes clothes = new Clothes();
//...造上衣;
return clothes;
}
}
//李宁工厂
public class LiNFactory implements IFactory {
@Override
public Pants createPants(){
Pants pants = new Pants();
//造一条裤子
return pants;
}
@Override
public Shoes createShoes(){
Shoes shoes = new Shoes();
//造一双鞋子
return shoes;
}
@Override
public Clothes createClothes(){
Clothes clothes = new Clothes();
//...造上衣;
return clothes;
}
}
//客户端代码。实例化不同的工厂子类,可以通过不同的创建方法创建不同的产品
public class Main {
public static void main(String[] args) {
IFactory liNFactory = new LiNFactory();
IFactory hxekFactory = new HXEKFactory();
//创造鸿星尔克上衣
Clothes hxekClothes = hxekFactory.createClothes();
//...
}
}
OK 本章结束,我们下期再见,看到这里,感谢您的阅读,如果觉得对您有帮助请 点赞收藏加关注!
我已经将本章收录在专题里,点击下方专题,关注专栏,我会每天发表干货,本月我会持续输入设计模式。
再次请求关注一下,创作不易,我这会儿写完已经10点半了,还在公司没有回家。加油! 我们下期再见