c#中的工厂模式

本文关键字:模式 工厂 | 更新日期: 2023-09-27 18:12:11

我有点能理解工厂模式,并想出了这个实现。

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函数应该接受enum类型,然后返回水果的权重。我可以得到一个特定的水果的对象,但现在我被如何从水果对象中得到水果的重量所困扰。

另外,为了增加我的疑问列表,我在这个实现中真的遵循工厂模式吗?还有,网上的一些材料也使用抽象类?我应该遵循什么?一个接口实现还是我应该使用一个抽象类并覆盖它?

提前感谢您的帮助。

c#中的工厂模式

如果您不打算在返回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(不要框)并在fruit实例上调用ReturnFruitWeight以获得权重。

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

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

网上的一些资料也使用抽象类吗?我应该遵循什么?一个接口实现还是我应该使用一个抽象类并覆盖它?

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

  • 有可以跨类共享的通用代码
  • 我需要一些方法来确定一个特定的类属于一个特定类型的家族,即BananaFruit的一个类型。

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

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

//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();
        }
    }

我会这样做:

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());
    }
}

不返回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 classinterface,两个选项都有效。如果你不想为你的方法提供默认实现,那么接口可能会更好,因为你可以实现多个接口,但你不能从多个类继承。