设计模式—抽象工厂模式

483 阅读4分钟

这是我参与新手入门的第3篇文章

概念

抽象工厂让客户能够使用抽象的接口来创建一组相关的产品,而不必关心实际生产出的产品是什么。这样,客户就能从具体的产品中解耦。

抽象工厂模式与工厂方法模式都可以很好的将对象的创建从代码中解耦出来,但这两种模式本质上还是有很大差别,抽象工厂更适用于有多个产品族的情况。

举例

书接上回。

之前,我们新开业的蛋糕店在开业的几天收获了不错的反响,吸引了大量的客户;所以为了提升用户的粘性,提高顾客对品牌的忠诚度,我们做了大量的市场调研。最终决定在保证原有品种纯蛋糕的产出质量的同时,推出其他在本地市场有极高竞争力的品种。

经过一段时间的经营,你的蛋糕店在本地已经有了不小的名气。你知道,是时候进行下一步了。

作为一名程序员,你深谙内卷之道。在当地,蛋糕这个市场早已经饱和,那么该如何从竞争对手那里争夺市场份额呢?

首先,你意识到资金必须足够。你先从之前的同事那里拉来了投资——什么财富自由,中年危机啦一顿蛊惑,最后还真让你拉成功了不少(真是个带e人)。

对外,你打算在在东城和西城等各个地区开连锁店。你知道,位置十分重要,要在覆盖城市的同时打压竞争对手的生存空间。然后,大量的广告宣传,迅速提高在本地的知名度。再接着就是打价格战,给客户大量的优惠,烧钱,以求垄断当地的市场,成为当地甚至更大区域的龙头后,资金就不是问题。

对内,你提高员工的薪水以及福利待遇,自愿劳动,就可以拿到比同行高的多的工资。作为一家良心企业,你是肯定是不鼓励加班的。企业管理也不能落下,企业文化和kpi双管齐下,再加上末尾淘汰优化机制,通过内部竞争,很好的保持了整个团队的战斗力。当然,你也同意本地其他店铺来加盟。一段时间之后,部分蛋糕店顶不住烧钱的压力选择加盟。

。。。

经过一段时间的努力,你成功将店铺开到了不同的城市。但是没过多久,你发现,加盟店制作的蛋糕味道和直营店的差别很大,有不少顾客反应蛋糕很难吃。原来,有一些加盟店,使用低价原料来增加利润。你必须采取一些手段,以免毁了招牌。要如何确保每家加盟店使用高质量的原料?你打算制造一个生产原料的工厂,并将原料送到各家加盟店。好,说干就干:

原料工厂

现在为工厂定义一个接口, 这个接口负责所有原材料的挑选。

public interface CakeMaterialFactory {
    public Flour createFlour();
    public Egg selectEgg();
    public Milk createMilk();
    public Sugar createSugar();
}

原料工厂(A1地区)

这里是A1地区的原料工厂,我们选材料不仅仅要考虑成本,还要考虑当地人的口味偏好

public class A1CakeMaterialFactory implements CakeMaterialFactory {

    public Flour createFlour() {
        return new LowGlutenFlour();
    }
    
    public Egg selectEgg() {
        return new NativeEgg();
    }
    
    public Milk createMilk() {
        return new SweetMilk();
    }
    
    public Sugar createSugar() {
        return new CasterSugar();
    }
}

其他地区的工厂也类似

蛋糕类

接下我们让蛋糕都使用从工厂产出来的高质量原料

public abstract class Cake {
    String name;
    // 以下都是蛋糕制作需要的一些原材料
    Flour flour;
    Egg egg;
    Milk milk;
    Sugar sugar;
    
    // 把材料选择的方法声明为抽象的,蛋糕的制作材料都来自我们的原料工厂
    abstract void materialSelection();
}

纯蛋糕

public class PlainCake extends Cake {

    CakeMaterialFactory factory;
    
    public PlainCake(CakeMaterialFactory factory) {
        this.factory = factory;
    }
    
    void materialSelection() {
        System.out.println("纯蛋糕材料获取");
        flour = factory.createFlour();
        egg = factory.selectEgg();
        milk = factory.createMilk();
        sugar = factory.createSugar();
    }
}

当然还有其他类型的蛋糕,不过大体上也类似。

原料

// 面粉
public interface Flour {
}

// 鸡蛋
public interface Egg {
}

// 牛奶
public interface Milk {
}

// 砂糖
public interface Sugar {
}

// 低筋面粉
public class LowGlutenFlour implements Flour {
}

// 本地鸡蛋
public class NativeEgg implements Egg {
}

// 甜牛奶
public class SweetMilk implements Milk {
}

// 细砂糖
public class CasterSugar implements Sugar {
}

让我们看一下类图来了解一下这种模式的结构:

classDiagram
Cake <|-- PlainCake
Cake <|-- SpongeCake
CakeMaterialFactory <|.. A1CakeMaterialFactory
CakeMaterialFactory <|.. B6CakeMaterialFactory

Cake : + String name
Cake : + Flour flour
Cake : + Egg egg
Cake : + Milk milk
Cake : + Sugar sugar
CakeMaterialFactory : + createFlour()
CakeMaterialFactory : + selectEgg()
CakeMaterialFactory : + createMilk()
CakeMaterialFactory : + createSugar()
interface CakeMaterialFactory


class A1CakeMaterialFactory {
 + createFlour()
 + selectEgg()
 + createMilk()
 + createSugar()
}

class B6CakeMaterialFactory {
 + createFlour()
 + selectEgg()
 + createMilk()
 + createSugar()
}

class PlainCake {
+String name
+materialSelection()
}

class SpongeCake {
+String name
+materialSelection()
}
classDiagram
Flour <|.. LowGlutenFlour
Egg <|.. NativeEgg
Milk <|.. SweetMilk
Sugar <|.. CasterSugar
interface CakeMaterialFactory
interface Flour
interface Egg
interface Milk
interface Sugar

可以看到,抽象工厂的每个方法实际上看起来都像是工厂方法,接口内的每一个方法都负责创建一个具体产品,我们通过实现抽象工厂的子类来实现每个产品的生成。

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

OK, 到这里我们就解决了原材料的问题。

下一步我们的蛋糕店是不是准备上市了呢?也许吧。。。

蛋糕店的故事到这里就结束了。