大话设计模式学习笔记-简单工厂模式

时间:2021-01-14 20:28:29

简单工厂模式

从父类派生出多个子类时,使用一个单独的类来做创造实例的过程,这就是工厂。

下面举出两个实例进行介绍简单工厂模式的应用。


简单计算器

每种计算都是获取数,返回结果的过程,故而可以将每种计算单独封装为一个类,并继承父类Operation。在父类中声明一个虚方法GetResult,每种计算子类都要重写父类该方法以进行自己的计算。

父类计算类:Operation

public class Operation{
    //两数的属性、获得结果虚方法
    public double NumbleA { get; set; }
    public double NumbleB { get; set; }
    public virtual double GetResult() => default(double);       
}

派生的子类:OperationAdd、Sub、Mul、Div

class OperationAdd : Operation{
    public override double GetResult() => NumbleA + NumbleB;
}
class OperationSub : Operation{
    public override double GetResult() => NumbleA - NumbleB;
}
class OperationMul : Operation{
    public override double GetResult() => NumbleA * NumbleB;
}
class OperationDiv : Operation{
    public override double GetResult(){
        if (NumbleB == 0) throw new Exception("除数不能为0");
        return NumbleA / NumbleB;
    }
}

工厂类:OperationFactory

class OperationFactory{
    //根据输入的运算符进行判断生成哪种子类的静态方法
    public static Operation CreateOperate(string operate){
        Operation oper = null;
        switch (operate){
            case "+":
                oper = new OperationAdd();
                break;
            case "-":
                oper = new OperationSub();
                break;
            case "*":
                oper = new OperationMul();
                break;
            case "/":
                oper = new OperationDiv();
                break;
        }
        return oper;
    }
}

测试类:Program

class Program{
    static void Main(string[] args){
        Console.WriteLine("请输入一个数:");
        double n1=Convert.ToDouble(Console.ReadLine());
        Console.WriteLine("请输入运算符:");
        var of=OperationFactory.CreateOperate(Console.ReadLine());
        Console.WriteLine("请输入一个数");
        double n2 = Convert.ToDouble(Console.ReadLine());
        of.NumbleA = n1;
        of.NumbleB = n2;
        Console.WriteLine($"运算结果为:{of.GetResult()}");
        Console.ReadKey();
    }
}

测试结果:控制台

请输入一个数:
5
请输入运算符:
/
请输入一个数
2
运算结果为:2.5

商场促销

商场促销的分类不应该细分折扣或者满减级别,这样类就特别多,分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。

商场促销有原价、打折、满减等手段,收银台需要根据不同的活动,将总价带入不同优惠的计算公式中得出最终的价格,所以打折算法才应该是一个类。

父类:现金收费抽象类

提供了一个接受现金抽象方法

abstract class CashSuper{
    public abstract double AcceptCash(double money);
}

子类:正常、打折、满减类

根据不同的优惠,将优惠方法分为若干个类,这些类都要继承现金收费抽象类并重写接受现金抽象方法。

class CashNormal : CashSuper{
    //返回原价
    public override double AcceptCash(double money) => money;
}
class CashRebate : CashSuper{
    //声明、初始化折扣
    private double moneyRebate = 1d;
    public CashRebate(double moneyRebate)=>this.moneyRebate = moneyRebate;
    //重写方法,计算折扣额
    public override double AcceptCash(double money) => money * moneyRebate;
}
class CashReturn : CashSuper{
    //声明、初始化满额和减额
    private double moneyCondition = default(double);
    private double moneyReturn = default(double);
    public CashReturn(double moneyCondition, double moneyReturn){
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }
    //重写方法,计算返回满减额
    public override double AcceptCash(double money){
        //将金额除以满额得到的数取整,乘以减额,得到满减额
        if (money >= moneyCondition)
            return money - Math.Floor(money / moneyCondition) * moneyReturn;
        return money;
    }
}

工厂类:现金工厂类

根据选择的不同优惠,创建对应的现金收费类的子类

class CashFactory{
    public static CashSuper CreateCashAccept(string type){
        CashSuper cs = null;
        switch (type){
            case "1":
                cs = new CashNormal();//原价
                break;
            case "2":
                cs = new CashRebate(0.8);//八折
                break;
            case "3":
                cs = new CashReturn(300,100);//满300返100
                break;
        }
        return cs;
    }
}

测试类:程序类

测试数据

class Program{
    static void Main(string[] args){
        Console.Write("请输入商品单价:");
        double foodSprice=double.Parse(Console.ReadLine());
        Console.Write("请输入商品数量:");
        double fooeNum = double.Parse(Console.ReadLine());
        Console.WriteLine($"1:原价{Environment.NewLine}2:八折{Environment.NewLine}3:满300返100");
        Console.Write("请选择优惠方式:");
        CashSuper cp=CashFactory.CreateCashAccept(Console.ReadLine());
        Console.WriteLine(cp.AcceptCash(foodSprice*fooeNum));
        Console.ReadKey();
    }
}

测试结果:控制台

请输入商品单价:200
请输入商品数量:5
1:原价
2:八折
3:满300返100
请选择优惠方式:3
700

注意

工厂类虽然能解决这个问题,但是这份模式只是解决对象的创建问题,工厂包括了所有的收费方式,每次维护或者扩展都要改动这个工厂,可以使用策略模式改进程序。