首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >工厂方法/抽象工厂模式的使用

工厂方法/抽象工厂模式的使用
EN

Stack Overflow用户
提问于 2018-11-12 20:11:34
回答 1查看 80关注 0票数 4

我有以下简化的需求,解析一个库存文件,其中包含汽车品牌的字母和相应的规范字符串在每一行。例如:

代码语言:javascript
复制
A Sedan
B Blue

下面我提供了代码的简化版本:

代码语言:javascript
复制
    class StockManager
    {
        List<ICar> cars = new List<ICar>();
        public StockManager(List<string> inventoryFileLines)
        {
            foreach(var inventoryFileLine in inventoryFileLines)
            {
                string[] parts = inventoryFileLine.Split(' ');
                cars.Add(CreateCar(parts[0], parts[1]));
            }
        }

        public decimal CalculateTotal()
        {
            decimal total = 0;
            foreach(var car in cars)
            {
                total += car.GetPrice();
            }
            return total;
        }

        public ICar CreateCar(string brand, string spec)
        {
            if(brand == "A")
            {
                return new CarA(spec);
            }else if(brand == "B")
            {
                return new CarB(spec);
            }
            throw new Exception();
        }
    }


    interface ICar
    {
        decimal GetPrice();
    }

    class CarA : ICar
    {
        string type;

        public CarA(string type)
        {
            this.type = type;
        }
        public decimal GetPrice()
        {
            if(type == "Sedan")
            {
                return 30000;
            }
            else if (type == "SUV")
            {
                return 50000;
            }
            throw new Exception();
        }
    }

    class CarB : ICar
    {
        string color;

        public CarB(string color)
        {
            this.color = color;
        }
        public decimal GetPrice()
        {
            if (color == "Orange")
            {
                return 20000;
            }else if (color == "Red")
            {
                return 25000;
            }
            throw new Exception();
        }
    }

在未来,可能会增加新的品牌和规格。这是我应该预见并提供灵活性的变化。现在,我想应用正确的设计模式,但应用它们的理由是正确的,而不仅仅是为了应用设计模式。(正如GoF所述:“只有在实际需要它提供的灵活性时,才应该应用设计模式。”)

我首先想到的是工厂的方法或抽象的工厂模式。因此,当有一个新的汽车品牌C是在未来添加:

工厂方法

使CreateCar是虚拟的,并在我将要使用的新StockManager类中重写它:

代码语言:javascript
复制
class StockManager2 : StockManager
{
    public StockManager2(List<string> inventoryFileLines) : base(inventoryFileLines) { }
    public override ICar CreateCar(string brand, string spec)
    {
        if (brand == "C")
        {
            ...
        }
        return base.CreateCar(brand, spec);
    }
}

抽象工厂

使CreateCar方法成为自己的抽象工厂类,并将其提供给StockManager类。

如果我想在运行时使用不同的替代创建选项,例如多个有效的CreateCar工厂,这两个重构看起来都很棒。GoF给出的迷宫例子也扩展了这一思想。

但事实上,我预期的改变并不是另一家工厂,而是一家经过改造的工厂。因此,在我看来,修改CreateCar方法比创建一个新的工厂类并使旧的类过时(这里代表抽象工厂方法)要合理得多。在工厂方法中,创建第二个StockManager2类也是如此。我知道开放/封闭原则( Robert的SOLID O)说不修改类,而是扩展类,而工厂模式正是这样做的,但是考虑到我在一开始提到的可扩展性要求,上面的示例是否证明了使用它的合理性?似乎需求不是在GoF中解释的扩展,而是真正的修改。但如果我错了,我希望得到纠正。

EN

回答 1

Stack Overflow用户

发布于 2018-11-12 20:53:29

您可以使用运行时对象创建机制。因此,c#将根据字符串创建类。惟一的期望类名和给定的字符串必须是相同的。

但是,如果值不相同,则可以使用静态字典。以下是代码:

代码语言:javascript
复制
public ICar CreateCar(string brand, string spec)
{
    System.Type type = typeof( ICar ).Assembly.GetTypes().Where( t => t.Name == brand ).FirstOrDefault();

    object instance = Activator.CreateInstance( type, new object[ 1 ] { specs } );
    return (ICar)instance;
}

当然,这个函数不处理任何错误,但它是容易的部分。顺便说一句,在您的代码中,请使用NotImplementedException而不是异常基类,因为这就是您想要的:)实现新品牌。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53269400

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档