工厂方法与抽象工厂

Posted yasoudream

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了工厂方法与抽象工厂相关的知识,希望对你有一定的参考价值。

本篇概述

工厂方法和抽象工厂都是一种对象创建型模式,在不同方面上解决了一些在对象创建上发生的设计问题。笔者学习的时候难以理解两者的区分,查阅较多资料后作此总结。

工厂方法 Factory Method

适用情况

当要根据不同的状况获取不同的类的实例对象时。
当一个类要实例化一个类对象却不知道该对象属于的类时。
总体来说就是要选择不同的类,延后实例化。

适用举例

工厂方法较为常用。
一款RPG游戏,一个铁匠铺要根据用户的输入打造不同类型的剑。

这种情况下,你事先不知道用户要打造哪个类型的剑,又不想将剑的类型在外部暴露出来,就可以使用工厂模式。

例示代码

代码主要展示结构设计,并不一定合乎使用情理,也不一定最优。
还要注意的是,虽然这里只是使用了普通的构造函数,但有很多对象的构造涉及较复杂的过程,使用工厂模式也能较好地将其过程封装起来。

基类

在这里我们用到两个基类,剑和剑工厂(这里就不用铁匠铺来描述了)

//剑的基类
public class Sword
{
    //一些代码
}

//铁匠铺
public class SwordFactory
{
    //这里设置成虚函数,使之可以被继承。为什么剑工厂会被继承,稍后会讲到。
    public virtual Sword CreateSword(string type)
    {
        switch (type)
        {
            case "LongSword":
            	return LongSword();
            //还有其他的剑的话可以在这里添加case代码
        }
        return Sword();
    }
}

衍生类

这里为了缩短篇幅只用一种剑举例,其他剑同理。

//长剑
public class LongSword : Sword
{
    //一些代码
}

使用

这样,我们就可以在不触及剑对象的创建和类型的前提下,根据情况创建需要的对象了。

SwordFactory sf = new SwordFactory();
Sword longSword = sf.CreateSword("LongSword");
//拿着长剑爱干嘛干嘛

适用举例2

后来,我们进入了魔界,魔界的铁匠铺能够生产恶魔之剑,但不能生产出长剑。
在先前,我们根本不知道恶魔之剑是什么,更别说实例化出恶魔之剑。这时,工厂模式继续发挥出他的作用。

例示代码2

我们不对基类做改变,而是使用一个新的工厂去继承原来的工厂。

衍生类

//魔剑
public class DevilSword : Sword
{
    //一些代码
}

//魔界铁匠铺
public class DevilSwordFactory
{
    //这里设置成虚函数,使之可以被继承。为什么剑工厂会被继承,稍后会讲到。
    public virtual Sword CreateSword(string type)
    {
        switch (type)
        {
            case "DevilSword":
            	return DevilSword();
            //还有其他的剑的话可以在这里添加case代码
        }
        return Sword();
    }
}

使用

这样,我们依旧可以在不暴露剑的类型和剑的制作方法的情况下获得一把魔剑的实例。

SwordFactory sf = new DevilSwordFactory();
Sword devilSword = sf.CreateSword("DevilSword");
//接下来带着魔剑爱干嘛干嘛

啥?你说你连铁匠铺都不想暴露?
那写个制造工厂的工厂不就好了 ??

总结

工厂模式是一个较为常用的设计模式,他的思想是借助其他对象实例化其他对象,可以有效将一部分代码封装(买剑不需要知道剑是怎么样生产出来的),或者将实例化的任务交给子类(魔界的铁匠铺才会打造魔剑)。但在类多的时候,有可能需要较多的工厂,造成类冗余。

在工厂只需要负责实例化一种对象时,C++可以用模板来解决类冗余的问题(由于笔者不会实现C#模板全特化,网上搜较多资料也未找到可行的方法,无法将书中的C++描述转化过来,这里就不多说了QAQ)

抽象工厂 Abstract Factory

适用情况

当创建的一系列对象存在互相依赖的关系时。

适用举例

在一款射击的游戏中,它有着这样的设定:
射击类武器有:手枪,步枪……。
每种射击类又有多种弹药:普通弹药,破甲型弹药……。
每种武器只能射击相对应的弹药,在捡到该武器的时候会赠送一些普通弹药。

在这种情况下,“子弹”和“枪”有了一定的联系,我们要生成一把射击类武器,就要生成对应的子弹。为了让用户生成的子弹和弹药类型必定匹配,我们就可以使用抽象工厂解决这一问题。

例示代码

代码主要展示结构设计,并不一定合乎使用情理,也不一定最优。

基类

首先,要有三个大基类:武器,弹药,工厂。
在这里三者都是抽象类。
这里为了缩短篇幅只用手枪举例,其他枪同理。

//弹药
public abstract class Bullet
{
    //代码,什么都行
}

//武器
public abstract class Gun
{
    //代码,什么都行
}

工厂:
由于抽象类无法实例化,这里利用静态方法来获取一个工厂的实例。
若设计的类有默认值,可使用其他方法获得实例,比如说基于一个List进行原型复制,或者单例。

public abstract class GunFactory
{
    //通过引索获得工厂的实例
    public static GunFactory GetFactory(string type)
    {
        switch (type)
        {
            case "Pistol":
                return new PistolFactory();
            //还有其他的工厂的话可以在这里添加case代码
        }
        return null;
    }
    public abstract Bullet CreateBullet();
    public abstract Gun CreateGun();
}

衍生类

//手枪弹药
public class PistolBullet : Bullet
{
	//代码
}

//手枪
public class Pistol: Gun
{
    //代码
}

//手枪工厂
public class PistolFactory : GunFactory
{
    public override Bullet CreateBullet()
    {
        return new PistolBullet();
    }

    public override Gun CreateGun()
    {
        return new PistolBullet();
    }
}

使用

通过静态方法实例化出工厂,就可以产出相匹配的枪和子弹了。

GunFactory pistolFac = GunFactory.GetFactory("Pistol");
Gun pistol = pistolFac.CreateGun();
Bullet bullet = pistolFac.CreateBullet();
//接下来爱干嘛干嘛

总结

抽象工厂主要的意图在于解决生成的多个对象相关联的问题。在没有关联的时候,由于要实现较多无用接口,使用抽象工厂反而会降低效率。

两者的比较

工厂方法:注重于对象的延迟生成,较多情况都可以使用,工厂可以只生产一种对象。
抽象工厂:注重于生成对象类型的关联性,在对象间有较强的关系时推荐使用,工厂一般要生成两种或以上对象(不然哪来的“关联”)

抽象工厂可以用也通常用工厂方法来实现(上面的例示代码便是用工厂方法实现),但同时也可以用原型模式来实现。















以上是关于工厂方法与抽象工厂的主要内容,如果未能解决你的问题,请参考以下文章

3.简单工厂模式工厂方法模式与抽象工厂模式

工厂模式—工厂方法与抽象工厂的战争

工厂方法与抽象工厂

设计模式与代码的结构特性

工厂模式与抽象工厂的区别

简单工厂工厂方法抽象工厂区别