设计模式学习(四)——工厂模式

一.需求

华兴镇以舒适美观的布鞋远近闻名,不光家家户户都会做,而且镇里有大大小小的布鞋厂十几家,订单源源不断……

王老板因为前些年家里做布鞋积累了一些资金,想着开办一家布鞋厂,扩大生产,扩展自己的生意。

一双布鞋主要是由两个主要部分组成:鞋面和鞋底。鞋底分为千层底、橡胶底、泡沫底,各有各的优点:千层底穿着舒适,橡胶底耐磨,泡沫底轻便。再说这鞋面,有棉布面料的,也有帆布面料的,还有绸缎面料的,棉布的柔软舒适,帆布的结实耐穿,绸缎的则美观大方。

为了能够快速打开市场,经过一番市场调研,王老板请设计师设计了三款布鞋,作为自己主打的产品:

  • 时尚款:泡沫底绸缎面料,既轻便又美观,主要面向年轻消费者
  • 经典款:橡胶底帆布面料,结实耐磨,主要面向大众消费者
  • 健康款:千层底棉布面料,穿着舒适透气,主要面向中老年消费者

王老板又在镇上招聘了10名工人,准备一有订单就开始生产。

产品有了,工人也有了,怎样组织自己的工厂进行生产,成了摆在王老板面前的又一道难题。哪些人生产鞋底?哪些人生产鞋面?哪些人进行鞋底鞋面合成加工?哪些人包装?各方如何配合?都是实实在在需要解决的生成问题。

二.解决方案

由于镇上的制鞋工人通常做鞋底、做鞋面、加工合成样样精通,在前期各个款式的受欢迎程度还不甚明朗的情况下,为了能够快速投入生产,王老板决定根据订单情况,让每个人独立负责布鞋生产的全流程。例如接到200双布鞋订单,其中时尚款100双,经典款100双,就组织5名工人生产时尚款,5名工人生产经典款。

// 抽象的布鞋类
abstract class Shoe {

    // 生产鞋面
    public abstract  void createVamp();

    // 生产鞋底
    public abstract void createSole();

    // 将鞋底与鞋面组合
    public abstract void combine();

}

// 时尚款布鞋
class FashionShoe extends Shoe {
    @Override
    public void createVamp() {
        System.out.println("生产时尚款鞋面");
    }

    @Override
    public void createSole() {
        System.out.println("生产时尚款鞋底");
    }

    @Override
    public void combine() {
        System.out.println("组装时尚款布鞋");
    }
}

// 经典款布鞋
class ClassicShoe extends Shoe {
    @Override
    public void createVamp() {
        System.out.println("生产经典款鞋面");
    }

    @Override
    public void createSole() {
        System.out.println("生产经典款鞋底");
    }

    @Override
    public void combine() {
        System.out.println("组装经典款布鞋");
    }
}

// 健康款布鞋
class HealthShoe extends Shoe {
    @Override
    public void createVamp() {
        System.out.println("生产健康款鞋面");
    }

    @Override
    public void createSole() {
        System.out.println("生产健康款鞋底");
    }

    @Override
    public void combine() {
        System.out.println("组装健康款布鞋");
    }
    
}

class ShoeFactary {

    public Shoe createShoes(String type) {
        Shoe shoe = null;
        if (type.equals("fashion")) {
            shoe = new FashionShoe();
        } else if (type.equals("classic")) {
            shoe = new ClassicShoe();
        } else if (type.equals("health")) {
            shoe = new HealthShoe();
        }
        shoe.createVamp();
        shoe.createSole();
        shoe.combine();
        return shoe;
    }

}

public class ShoeAdmin {
    public static void main(String[] args) {
        ShoeFactary shoeFactary = new ShoeFactary();
        shoeFactary.createShoes("fashion");
        shoeFactary.createShoes("health");
    }
    
}

运行程序:

生产时尚款鞋面
生产时尚款鞋底
组装时尚款布鞋
生产健康款鞋面
生产健康款鞋底
组装健康款布鞋

看起来还不错,只要指定布鞋的款式,工人们就可以进行生产了。

该方案的类图如下:

开业一个月以后,由于王老板的布鞋做工精良,款式新颖,获得了良好的市场反响,订单接踵而至。随着订单量持续上升,王老板的工厂不断扩大,后来已经有将近100名工人了。王老板一个人显然已经管理不了这么多员工了,为了能加强管理,王老板雇了一名经理负责工人们的生产管理。

经理在经过一番实地考察后,发现了生产当中的问题:由于每个工人随着订单的不同,有时生产时尚款,有时又生产经典款,经常需要来回切换,又因为不同款式的布鞋的生产工艺和需要使用的机器都不尽相同,因此工人们经常是刚刚在一台机器前完成一双布鞋的生产,又跑到另一台机器前去加工另一双布鞋,如此一来,效率大大折扣。

经理立即向王老板建议:将工厂划分为三个车间,每个车间只生产一种款式的布鞋。如此一来,就避免了一个工人在不同种类的布鞋生产间切换的问题,效率大大提高。

// 制鞋工厂
abstract class ShoeFactary {
    public abstract Shoe createShoes();
}

// 时尚款布鞋生产工厂,只生产时尚款布鞋
class FashionShoeFactary extends ShoeFactary {
    @Override
    public Shoe createShoes() {
        Shoe shoe = new FashionShoe();
        shoe.createSole();
        shoe.createVamp();
        shoe.combine();
        return shoe;
    }
}

// 经典款布鞋生产工厂,只生产经典款布鞋
class ClassicShoeFactary extends ShoeFactary {
    @Override
    public Shoe createShoes() {
        Shoe shoe = new ClassicShoe();
        shoe.createSole();
        shoe.createVamp();
        shoe.combine();
        return shoe;
    }
}

// 健康款布鞋生产工厂,只生产健康款布鞋
class HealthShoeFactary extends ShoeFactary {
    @Override
    public Shoe createShoes() {
        Shoe shoe = new HealthShoe();
        shoe.createSole();
        shoe.createVamp();
        shoe.combine();
        return shoe;
    }
}

public class ShoeAdmin {
    public static void main(String[] args) {
        ShoeFactary fashionFactary = new FashionShoeFactary();
        ShoeFactary healthFactary = new HealthShoeFactary();
        fashionFactary.createShoes();
        healthFactary.createShoes();
    }

}

运行代码:

生产时尚款鞋面
生产时尚款鞋底
组装时尚款布鞋
生产健康款鞋面
生产健康款鞋底
组装健康款布鞋

类图如下:

如此一来,一切就井然有序了,时尚款步鞋车间的工人只生产时尚款布鞋,经典款鞋车间的工人只生产经典款布鞋,大家各司其职,紧张有序的进行着布鞋生产。

两年后,王老板的布鞋厂已经拥有500名员工了,业已成为华兴镇最大的布鞋厂商了,王老板满面春风,对自己长取得的成绩很是满意。然后王老板也知道创业维艰,竞争激烈,每个月都会组织各个车间的主任进行开会,讨论生产中的问题。

在最近的一次生产大会上,年轻的车间主任小李提出:每个工人要负责一双布鞋的全部流程:做鞋面、做鞋底、合成、包装,工人需要在各个流程间来回切换,细心的小李已经发现,一些有经验的工人师傅并不是一双鞋做完再做另一双鞋,而是做好了几个鞋底,再做好了几个鞋面之后,再进行合成,最后再包装,这样一来,就比那些一双接着一双做的师傅效率提升了不少。小李提出了一个大胆的想法:将工厂重新划分为6个车间,其中3个车间生产鞋底和鞋面(一个车间只生产时尚款的鞋底和鞋面,一个车间只生产经典款的鞋底和鞋面,一个车间只生产健康款的鞋底和鞋面),另外3个车间只负责布鞋的组装(3款鞋的组装由3个车间独立负责),组装车间依赖对应款式的鞋底鞋面生产车间。

这个想法一提出,全场瞬间炸开了锅,经过一番激烈讨论,王老板决定按照小李的办法试行一段时间:

// 鞋面
abstract class Vamp {
    public abstract void descripe();
}

// 时尚布鞋鞋面
class FashionVamp extends Vamp {
    @Override
    public void descripe() {
        System.out.println("时尚款鞋面");
    }
}

// 经典款鞋面
class ClassicVamp extends Vamp {
    @Override
    public void descripe() {
        System.out.println("经典款鞋面");
    }
}

// 健康款鞋面
class HealthVamp extends Vamp {
    @Override
    public void descripe() {
        System.out.println("健康款鞋面");
    }
}

// 鞋底
abstract class Sole {
    public abstract void descripe();
}

// 时尚款鞋底
class FashionSole extends Sole {
    @Override
    public void descripe() {
        System.out.println("时尚款鞋底");
    }
}

// 经典款鞋底
class ClassicSole extends Sole {
    @Override
    public void descripe() {
        System.out.println("经典款鞋底");
    }
}

// 健康款鞋底
class HealthSole extends Sole {
    @Override
    public void descripe() {
        System.out.println("健康款鞋底");
    }
}


// 抽象的布鞋类
abstract class Shoe {

    // 生产鞋面
    public abstract  void createVamp();

    // 生产鞋底
    public abstract void createSole();

    // 将鞋底与鞋面组合
    public abstract void combine();

}

// 时尚款布鞋
class FashionShoe extends Shoe {

    private ShoeComponentFactory shoeComponentFactary;

    public FashionShoe(ShoeComponentFactory shoeComponentFactary) {
        this.shoeComponentFactary = shoeComponentFactary;
    }
    @Override
    public void createVamp() {
        shoeComponentFactary.createVamp();
        System.out.println("生产时尚款鞋面");
    }

    @Override
    public void createSole() {
        shoeComponentFactary.createSole();
        System.out.println("生产时尚款鞋底");
    }

    @Override
    public void combine() {
        System.out.println("组装时尚款布鞋");
    }
}

// 经典款布鞋
class ClassicShoe extends Shoe {

    private ShoeComponentFactory shoeComponentFactary;

    public ClassicShoe(ShoeComponentFactory shoeComponentFactary) {
        this.shoeComponentFactary = shoeComponentFactary;
    }
    @Override
    public void createVamp() {
        shoeComponentFactary.createVamp();
        System.out.println("生产经典款鞋面");
    }

    @Override
    public void createSole() {
        shoeComponentFactary.createSole();
        System.out.println("生产经典款鞋底");
    }

    @Override
    public void combine() {
        System.out.println("组装经典款布鞋");
    }
}

// 健康款布鞋
class HealthShoe extends Shoe {

    private ShoeComponentFactory shoeComponentFactary;

    public HealthShoe(ShoeComponentFactory shoeComponentFactary) {
        this.shoeComponentFactary = shoeComponentFactary;
    }
    @Override
    public void createVamp() {
        shoeComponentFactary.createVamp();
        System.out.println("生产健康款鞋面");
    }

    @Override
    public void createSole() {
        shoeComponentFactary.createSole();
        System.out.println("生产健康款鞋底");
    }

    @Override
    public void combine() {
        System.out.println("组装健康款布鞋");
    }

}

abstract class ShoeComponentFactory {
    public abstract Vamp createVamp();

    public abstract Sole createSole();
}

class FashionShoeComponentFactory extends ShoeComponentFactory {
    @Override
    public Vamp createVamp() {
        return new FashionVamp();
    }

    @Override
    public Sole createSole() {
        return new FashionSole();
    }
}

class ClassicShoeComponentFactory extends ShoeComponentFactory {
    @Override
    public Vamp createVamp() {
        return new ClassicVamp();
    }

    @Override
    public Sole createSole() {
        return new ClassicSole();
    }
}

class HealthShoeComponentFactory extends ShoeComponentFactory {
    @Override
    public Vamp createVamp() {
        return new HealthVamp();
    }

    @Override
    public Sole createSole() {
        return new HealthSole();
    }
}
// 抽象的工厂
abstract class ShoeFactary {
    public abstract Shoe createShoes();
}

// 时尚款布鞋生产工厂,只生产时尚款布鞋
class FashionShoeFactary extends ShoeFactary {
    private ShoeComponentFactory shoeComponentFactory = new FashionShoeComponentFactory();

    @Override
    public Shoe createShoes() {
        Shoe shoe = new FashionShoe(shoeComponentFactory);
        shoe.createVamp();
        shoe.createSole();
        shoe.combine();
        return shoe;
    }
}

// 经典款布鞋生产工厂,只生产经典款布鞋
class ClassicShoeFactary extends ShoeFactary {
    private ShoeComponentFactory shoeComponentFactory = new ClassicShoeComponentFactory();

    @Override
    public Shoe createShoes() {
        Shoe shoe = new ClassicShoe(shoeComponentFactory);
        shoe.createVamp();
        shoe.createSole();
        shoe.combine();
        return shoe;
    }
}

// 健康款布鞋生产工厂,只生产健康款布鞋
class HealthShoeFactary extends ShoeFactary {
    private ShoeComponentFactory shoeComponentFactory = new HealthShoeComponentFactory();

    @Override
    public Shoe createShoes() {
        Shoe shoe = new HealthShoe(shoeComponentFactory);
        shoe.createVamp();
        shoe.createSole();
        shoe.combine();
        return shoe;
    }
}

public class ShoeAdmin {
    public static void main(String[] args) {
        ShoeFactary fashionFactary = new FashionShoeFactary();
        ShoeFactary healthFactary = new HealthShoeFactary();
        fashionFactary.createShoes();
        healthFactary.createShoes();
    }
}

运行代码:

生产时尚款鞋面
生产时尚款鞋底
组装时尚款布鞋
生产健康款鞋面
生产健康款鞋底
组装健康款布鞋

类图如下:

在上面这个实现方案中,我们增加了布鞋组件生产工厂,只负责生产鞋面、鞋底,布鞋工厂直接从相应的组件工厂获取所需的鞋面和鞋底即可。想生产何种布鞋,只需要找相应的工厂生产即可。如此,各司其职,效率大大提高。

四.模式总结

我们在上面一共给出了三种解决方案,第一种方案使用了简单工厂,第二种方案使用了工厂方法模式,第三种方案使用了抽象工厂模式。准确的来说,简单工厂并不是一种设计模式,而是一种编程习惯。

我们再回过头来逐一看看这三种工厂:

1.简单工厂
类图
简单工厂模式

在工厂中声明一个方法用于获取产品,方法接收一个参数用于说明需要的产品类型,该方法根据type生产出对应的产品并返回。

应用场景

某种产品有几种不同类型,需要根据需要获取不同类型的产品。

优点

(1)将产品的生产与产品的使用逻辑分离,两部分互不影响,且提高复用性
(2)简单易用

缺点

当需要新增产品类型时,需要修改getProduct方法,违反了开闭原则。

2.工厂方法
类图
工厂方法模式

在工厂方法模式中,与简单工厂最大的区别是产品的生产交给了子类工厂,这样一来需要何种产品只需要找到相应的工厂即可。举个例子:简单工厂是杂货店,想买东西需要跟老板说,如果有就卖给你,没有就告诉你没有;工厂方法则是一条商业街,每个商店只卖一种东西,有花店,玩具店,化妆品店……想要什么东西就去什么店铺就行了,如果没有这种店铺就说明没有这种东西。

应用场景

当需要由子类来决定需要的产品类型时,可以充分利用工厂的抽象接口针对接口编程,子类利用具体的工厂实现具体的产品生产。

优点

(1)与简单工厂一样具有隔离产品生产与产品使用的优点
(2)灵活,具体的产品生产细节由具体工厂实现,能够借助多态灵活运用
(3)扩展性强,新增产品只需要添加新的产品类型,并添加相应的工厂,原有代码无需修改,符合开闭原则

缺点

当需要新增产品类型时,需要同时增加产品类和对应工厂类,增加维护成本与整体复杂性。

3.抽象工厂
类图
抽象工厂模式

抽象工厂与工厂方法最大的不同在于抽象工厂主要面向有关联关系的产品家族的生产。每种特定工厂可以生成一个产品家族的各种产品。这里涉及到两个概念:

产品等级结构:产品等级结构即产品的继承结构,在我们上面布鞋厂的例子当中,时尚款布鞋和经典款布鞋、健康款布鞋就是不同的产品等级结构。
产品族:产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。同样拿布鞋厂的例子来说,鞋底和鞋面就是一个产品族。时尚组件厂生产的是时尚款的鞋底和鞋面,经典组件厂生产的经典款鞋底和鞋面。

应用场景

系统中存在产品等级和产品族的概念,且同一个产品族中的产品需要被一起使用。

优点

(1)能够从设计上保证一个工厂生产出来的产品是同一个家族的,当有这种需求时,使用抽象工厂是一种优雅的设计
(2)同样符合开闭原则

缺点

当产品族增加新成员时需要同时新增产品类,也需要修改工厂类添加新的方法,较为繁琐。

以上就是与工厂有关的三种模式,各有利弊,使用时可根据具体需求来选择使用。

参考资料

本文已迁移至我的博客:http://ipenge.com/16325.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 1.一个是什么样的人就会做什么样的事,他做什么样的事就是什么样的人。
    碧海蓝天lin阅读 91评论 0 0
  • 睡海阅读 143评论 0 0
  • 死亡 彻彻底底地睡去 彻彻底底地把自己交还回去 这造化人的自然,让 我把所有的一切都忘却 同时忘却的还有你 躺下来...
    沙鸻阅读 147评论 0 2