C#中的工厂模式

时间:2013-05-06 08:20:20

标签: c# .net design-patterns .net-4.5

我有点能理解Factory Pattern并想出了这个实现。

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Enter the fruit name to get the Fruit!");
        string fruit = Console.ReadLine();

        FruitsList fruits;
        if (Enum.TryParse(fruit, true, out fruits))
        {
            var fruitWeight = GetFruitWeight(fruits);
            Console.ReadLine();
        }
        else
        {
            Console.WriteLine("Fruit Name is undefined!");
            Console.ReadLine();
        }
    }

    private static object GetFruitWeight(FruitsList fruitNumber)
    {
        switch (fruitNumber)
        {
            case FruitsList.Banana:
                return new Banana();
            case FruitsList.Apple:
                return new Apple();
        }

        return null;
    }
}

internal class Banana : IFruits
{
    public float ReturnFruitWeight()
    {
        return (float)10.00;
    }
}

public interface IFruits
{
    float ReturnFruitWeight();
}

public class Apple : IFruits
{
    public float ReturnFruitWeight()
    {
        return (float)30.00;
    }
}

public enum FruitsList
{
    Apple,
    Banana,
}

我的整个想法(来自理论上的理解)是GetFruitWeights函数应接受枚举类型然后返回果实重量。我能够得到一个特定的水果的对象,但现在我对水果对象的方式感到困惑,我得到了水果的重量。

另外,要添加到我的疑惑列表中,我是否真的遵循此实现中的Factory模式?而且,互联网上的一些材料也使用抽象类?我该怎么办?接口实现还是应该使用抽象类并覆盖它?

提前感谢您的帮助。

4 个答案:

答案 0 :(得分:4)

如果您在返回时无意使用fruit对象,那么我只是直接返回权重而不是水果对象。工厂方法名实际上确实说它返回了权重,而不是对象,所以在理论上它是正确的方法,即

const float AppleWeight = 10;
const float BananaWeight = 10.4;
...
public static float GetFruitWeight(FruitList fruitType)
{
    switch (fruitType)
    {
        case FruitsList.Apple:
            return AppleWeight;
        case FruitsList.Banana:
            return BananaWeight;
        default:
            return 0;
    }
}

但是,如果您打算使用fruit对象,那么我会将您的方法重命名为GetFruit,返回IFruits(不要选中)并致电ReturnFruitWeightfruit重量实例上。

  

我是否真的在这个实现中遵循工厂模式?

工厂模式的要点是允许你在不知道具体类型的情况下创建对象,所以你在这里拥有的是工厂方法模式的一个相当基本的例子。

  

互联网上的一些材料也使用抽象类?我该怎么办?接口实现还是应该使用抽象类并覆盖它?

这完全取决于您的应用程序设计。例如,我个人只会在以下情况下引入抽象基类:

  • 我可以在各个课程中分享共同的代码
  • 我需要一些方法来确定特定类属于特定类型的家庭,即BananaFruit的类型。

除此之外,我可能几乎总是采用接口类型的方法。请记住,你可以同时拥有这两者,没有理由不能拥有支持特定接口的抽象基类......

答案 1 :(得分:3)

您可以按照抽象类型或接口方法来实现工厂方法。例如,您的案例可以通过抽象来解决,因为您打算返回一个子类。

//Fruit base
    public abstract class Fruit
    {
        protected abstract string GetWeight();
    }
    public class Apple:Fruit
    {
        protected override string GetWeight()
        {
            return "I am from Apple";//replace with your implementation
        }
    }
    public class Banana : Fruit
    {
        protected override string GetWeight()
        {
            return "I am from Banana";//replace with your implementation
        }
    }



private static Fruit GetFruitWeight(string fruitNumber)
        {
            switch (fruitNumber)
            {
                case "Banana":
                    return new Banana();
                case "Apple":
                    return new Apple();
            }

            return null;
        }

现在我们应该在哪里使用接口方法?

就个人而言,我在工厂方法中遵循接口方法,我期望返回服务。例如。假设一个返回电子邮件发件人服务的工厂方法,我可以在其中为outlook或其他电子邮件服务实现服务。

public class Outlook:ISender
    {

        public void SendEmail()
        {
            //Write implementation on how OL send email.
        }
    }
    public class OtherEmail : ISender
    {

        public void SendEmail()
        {
            //Write implementation on how other email send email.
        }
    }
    public interface ISender
    {
        void SendEmail();
    }
    public class EmailFactory
    {

        public static ISender GetEmailProvider(string type)
        {
            if (type == "outlook")
                return new Outlook();
            return new OtherEmail();
        }
    }

答案 2 :(得分:1)

不要返回object,而是IFruits。此外,重命名静态方法,因为它返回水果,而不是它们的重量:

private static IFruits GetFruit(FruitsList fruitNumber)
{
    switch (fruitNumber)
    {
        case FruitsList.Banana:
            return new Banana();
        case FruitsList.Apple:
            return new Apple();
    }

    return null;  // Maybe you can throw a ArgumentException here
}
...
var theFruit = GetFruit(fruits);
var weight = theFruit.ReturnFruitWeight();

对于abstract class vs interface,这两个选项都有效。如果您不想为方法提供默认实现,那么接口可能会更好,因为您可以实现多个接口但不能从多个类继承。

答案 3 :(得分:0)

我会做这样的事情:

public interface IFruit
{
    string Name { get; set; }
    decimal GetWeight();
}

public class Fruit : IFruit
{
    protected decimal Weight;

    public string Name { get; set; }

    public decimal GetWeight()
    {
        return Weight;
    }
}

public class Apple : Fruit
{
    public Apple()
    {
        Name = "Granny Smith";
        Weight = (decimal) 2.1;
    }
}

public class Banana : Fruit
{
    public Banana()
    {
        Name = "Cavendish";
        Weight = (decimal) 1.5;
    }
}

public enum FruitType
{
    Apple,
    Banana        
}

public static class FruitFactory
{
    public static IFruit CreateFruit(FruitType f)
    {
        switch(f)
        {
            case FruitType.Banana: return new Banana();
            case FruitType.Apple: return new Apple();
            default: return null;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var apple = FruitFactory.CreateFruit(FruitType.Apple);
        var banana = FruitFactory.CreateFruit(FruitType.Banana);

        Console.WriteLine(apple.Name + " " + apple.GetWeight());
        Console.WriteLine(banana.Name + " " + banana.GetWeight());
    }
}