(3)创建型模式——工厂方法

创建型模式——工厂方法(Factory Method)

问题背景

为了引出问题,我们首先介绍一种未被纳入GoF设计模式的模式:简单工厂。这个模式是为了将某个接口的某个实现的创建和表示分离而存在的。听起来似乎有点晦涩,下面举个例子。在LOL的载入过程中,游戏要根据玩家在房间的选择来创建对应的英雄。由于英雄的创建过程比较复杂,所以考虑将创建工作交给工厂。假设每个英雄都是一个类,他们都实现了IChampion接口,那么使用简单工厂的代码是这样的:

public IChampion CreateChampion(string name)
{
    switch (name)
    {
        case "Yasuo":
            return new Yasuo();
        case "Lee Sin":
            return new LeeSin();
        // ...
        default:
            throw new Exception("无此英雄");
    }
}

对于英雄联盟这种三天两头就要出新英雄骗氪的游戏来说,这么做无疑会增加工作难度,因为每次出新英雄都得修改工厂。

解决方案

以上问题的根源在于需求的不稳定性,试想如果游戏发布之后就不再更新,那么简单工厂是完全无可非议的。但面对这种发布后需要运营和迭代的产品,就要考虑工厂方法了。工厂方法仅仅规定一个创建对象的接口,但不负责实现,具体的实现工作延迟到它的实现类中。改进后的程序结构是这样的:
程序结构
使用工厂方法之后,当新增英雄时,只需要分别扩展IChampion和IChampionFactory,不需要修改原有代码。

效果

  1. 将对象的创建工作与应用代码解耦。
  2. 避免了在需求变化时修改原有代码。

缺陷

工厂类的存在使项目中类的数量翻倍,在大型项目中会造成类爆炸。

目前,主流编程语言大都支持元编程,工厂方法一般会基于反射实现,而不是基于接口。基于反射的工厂不存在类爆炸的问题,是当前的主流做法,这种工厂会在第二期的《反射工厂》中介绍。

相关模式

  1. 抽象工厂:工厂方法是抽象工厂的一种常见实现方式。
  2. 单例:工厂类常被设计成单例类。

实现

using System;

namespace FactoryMethod
{
    class Client
    {
        public interface IChampion
        {
            void Show();
        }
        public interface IChampionFactory
        {
            IChampion CreateChampion();
        }

        public class Yasuo : IChampion
        {
            public void Show()
            {
                Console.WriteLine("死亡如风,常伴吾身");
            }
        }

        public class LeeSin : IChampion
        {
            public void Show()
            {
                Console.WriteLine("我用双手成就你的梦想");
            }
        }

        public class YasuoFactory : IChampionFactory
        {
            public IChampion CreateChampion()
            {
                return new Yasuo();
            }
        }

        public class LeeSinFactory : IChampionFactory
        {
            public IChampion CreateChampion()
            {
                return new LeeSin();
            }
        }

        static void Main(string[] args)
        {
            Console.WriteLine("创建亚索...");
            IChampionFactory factory = new YasuoFactory();
            var yasuo = factory.CreateChampion();
            yasuo.Show();

            Console.WriteLine("创建盲僧...");
            factory = new LeeSinFactory();
            var leesin = factory.CreateChampion();
            leesin.Show();
        }
    }
}

运行结果

发布了10 篇原创文章 · 获赞 10 · 访问量 484

猜你喜欢

转载自blog.csdn.net/DIAX_/article/details/104142719