【问题标题】:Factory Design Pattern - Why Interface necessary?工厂设计模式——为什么需要接口?
【发布时间】:2013-12-22 12:19:05
【问题描述】:

我开始研究不同的设计模式,现在我专注于工厂设计模式。我查看了一些示例、youtube tuturials 和博客,我得到的最多,但我仍然不明白为什么需要一个界面。

官方定义是:

定义创建对象的接口,但让子类决定 要实例化哪个类。工厂方法让一个类延迟 实例化到子类。

所以接口似乎是工厂设计模式的重要组成部分,但我发现它实用的唯一原因是你在 main 方法中创建一个集合。如果你不想这样,你可以删除它(看看下面的代码,如果可能的话)它仍然像计划的那样工作。

using System;
using System.Collections.Generic;
using System.Collections;

namespace FactoryDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            var FordFiestaFactory = new FordFiestaFactory();
            var FordFiesta = FordFiestaFactory.CreateCar("Blue");
            Console.WriteLine("Brand: {0} \nModel: {1} \nColor: {2}", FordFiesta.Make, FordFiesta.Model, FordFiesta.Color);
            Console.WriteLine();


            //Inserted this later. Using a collection requires the Interface to be there.
            List<ICreateCars> Cars = new List<ICreateCars>();
            Cars.Add(new FordFiestaFactory());
            Cars.Add(new BMWX5Factory());

            foreach (var Car in Cars)
            {
                var ProductCar = Car.CreateCar("Red");
                Console.WriteLine("Brand: {0} \nModel: {1} \nColor: {2}", ProductCar.Make, ProductCar.Model, ProductCar.Color);
                Console.WriteLine();
            }

            Console.ReadKey();
        }
    }

    public abstract class Car
    {
        public string Make { get; set; }
        public string Model { get; set; }
        public string EngineSize { get; set; }
        public string Color { get; set; }
    }

    public class FordFiesta : Car
    {
        public FordFiesta()
        {
            Make = "Ford";
            Model = "Fiesta";
            EngineSize = "1.1";
        }
    }

    public class BMWX5 : Car
    {
        public BMWX5()
        {
            Make = "BMW";
            Model = "X5";
            EngineSize = "2.1";
        }
    }

    public interface ICreateCars
    {
        Car CreateCar(string color);
    }

    class FordFiestaFactory : ICreateCars
    {
        public Car CreateCar(string color)
        {
            return new FordFiesta() { Color = color };
        }
    }

    class BMWX5Factory : ICreateCars
    {
        public Car CreateCar(string color)
        {
            return new BMWX5(){ Color = color };
        }
    }
}

那么为什么我需要那个接口呢?我阅读了多个抽象的解释,但我没有明白,所以我更喜欢实用的答案。

提前致谢!

【问题讨论】:

  • 这个上下文中的接口一般有“接口”的字面意思..不是.NET意义上的接口。

标签: c# design-patterns factory factory-pattern


【解决方案1】:

当工厂的调用者不知道工厂的类型时,接口(或抽象工厂基类,本质上与实际的接口相同)很有用。

您为自己的实际示例提供了基础,因此我将在此处添加我的解释,为什么这不仅在拥有工厂列表时有用:

想象一个方法,它应该在适当的时候创建汽车,而不知道要创建什么类型的汽车(这由工厂实现决定)。该方法查看Person 对象,该对象具有OwnsCar 属性,而 属性最终决定是否应调用工厂方法:

public Car CreateCarForPerson(Person person, ICreateCars carType)
{
    if (person.OwnsCar) {
        return carType.CreateCar("red");
    } else {
        return null;
    }
}

同样,您也可以使用这样的工厂来创建任意数量的汽车:

public Car[] CreateAnyNumberOfCars(ICreateCars carType)
{
    var result = new List<Car>();
    for (int i = new Random().Next(100); i >= 0; i--) {
        result.Add(carType.CreateCar("blue"));
    }
    return result.ToArray();
}

请注意,这两种方法都不知道正在创建的汽车类型;他们使用只知道接口但不知道确切类型的工厂。

因此,如果您希望能够提供不同的工厂实现,您可以为您的工厂声明一个通用接口。如果你的工厂只是为了让你的调用者远离目标构造函数的直接调用,你就不需要工厂接口。

【讨论】:

    【解决方案2】:

    您始终可以按照自己喜欢的方式应用设计模式。删除接口没有错。但是,您应该考虑到删除接口会导致结构不太通用。

    您使用factory pattern 是因为您不希望您的调用代码(主函数)了解有关构造细节的任何信息。你不想知道什么是 FordFiest。你只想要一辆一般的汽车。如果是福特嘉年华,那就这样吧。这个细节是工厂(及其子类)应该处理的。对吧?

    如果你不希望你的代码依赖于特定的工厂,你需要一个额外的抽象层,由接口提供,导致这两个部分“解耦”。如果你不'不介意你的代码绑定到特定的工厂实现,你可以随时删除接口。

    希望我能帮上忙!

    【讨论】:

      【解决方案3】:

      当然您可以使用CarFactory 创建派生汽车类,但是每个想要支持创建汽车的人都必须从CarFactory 派生。在我看来,界面的目的是让谁可以充当汽车工厂更加灵活。这个概念是 all 你需要做的是在这个例子中成为CarFactory 是实现ICreateCars 接口。无需引入交付的CarFactory 基类的开销。

      关键在于决定您在接受汽车工厂的函数上的参数类型。 (或者存储CarFactory 的成员的成员类型是什么)如果您使用ICreateCars,那么任何想要创建汽车的人只需要实现该接口。如果您的参数类型是CarFactory,那么它们必须继承自CarFactory

      【讨论】:

        【解决方案4】:

        嗯,不是真的——接口不是这个模式的一个组成部分。您可以像实现静态类甚至普通类一样好地实现工厂。

        只是使用接口通常是一个非常好的主意,大多数基于组件的设计都大量使用了这一点。它被称为Interface based programming,它的主要优点之一是它允许 IoC 容器并且它使您的代码可测试。

        就我个人而言,我几乎是盲目地使用接口,甚至没有考虑过......

        【讨论】:

          【解决方案5】:

          接口让您可以记录一组类,这些类支持一组特定的多态方法,而无需创建继承层次结构来链接所有类。

          如果没有接口,设计者将不得不创建一个他们都继承自的人工基类。当一个类需要实现两组不同的多态方法时,这是不可能的。

          多重继承是语言设计者想要避免的,因为不清楚当一个类有两个父类时应该调用什么方法。除此之外,实现的人为继承总是很尴尬。

          从根本上说,接口允许您在不继承任何实现的情况下继承方法定义。

          【讨论】:

            【解决方案6】:

            工厂模式的目的是抽象创造。在这种情况下,将有可能以适当的实现交换工厂。

            抽象可以通过.NET中的接口或抽象类来实现。

            public interface ICreateCars
            {
                Car CreateCar(string color);
            }
            

            构建结果(Car)可以是类也可以是接口,看情况。如何构建它是工厂的工作。

            【讨论】: