首页 > 代码库 > 【大话设计模式】——简单工厂模式
【大话设计模式】——简单工厂模式
一、概念
简单工厂模式(Simple Factory Pattern)属于创建型模式,又叫做静态工厂方法模式(Static FactoryMethod Pattern),但是不属于23GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
二、UML图
简单工厂主要分为三个角色:工厂(Creator)角色、抽象产品(Product)角色、具体产品(Concrete Product)角色。
工厂角色:该模式核心,它负责创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需要的产品。
抽象产品角色:所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品:该模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
三、实例解析
以下是我自己想的一个简单工厂模式场景,如果有不妥的地方还请大家指出。
我做的是一个简易的网吧收费系统,CashFactory充当的是工厂的角色,它会告诉我们如何创建白天收费方式和晚上收费方式,需要实例化哪些对象,需要什么参数;具体产品 白天、晚上 收费方法,通过override,实现了从基类继承成员的新实现。网吧收费抽象类 为白天和晚上 收费方式的父类,描述了两者的公共接口。
代码如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication2 { public partial class 简易网吧收费系统 : Form { public 简易网吧收费系统() { InitializeComponent(); } //窗体启动的时候加载收费方式,是晚上收费,还是白天收费 private void Form1_Load(object sender, EventArgs e) { cbxTimeType.Items.AddRange(new object[] { "白天", "晚上" });//在时间段的选择框里加载收费选项 白天,晚上 cbxTimeType.SelectedIndex = 0;//索引从0开始,从下往上依次递增 } //单击开始按钮之后,收费系统开始计时 private void btnOK_Click(object sender, EventArgs e) { lbxList.Items.Add(cbxTimeType .Text ); txtStartTime.Text = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");//开始时间文本框获取开始时间 lbxList.Items.Add("开始时间:" + txtStartTime.Text);//同时在下面的列表框中加载开始时间信息 } //单击停止按钮后,收费系统停止计时 private void btnStop_Click(object sender, EventArgs e) { txtEndTime.Text = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"); lbxList.Items.Add("结束时间:" + txtEndTime.Text); } //单击结账按钮,系统开始结账 private void btnCharge_Click(object sender, EventArgs e) { double timeThrough = 0.0d;//定义一个变量timeThrough代表花费的时间(小时) DateTime DateTime1, DateTime2;//定义两个时间变量 DateTime1 = Convert.ToDateTime(txtStartTime.Text);//把文本框中的时间从字符串格式转换成时间格式 DateTime2 = Convert.ToDateTime(txtEndTime.Text); string DateDiff = null;//定义变量时间差(x天x小时x分钟x秒) TimeSpan ts1 = new TimeSpan(DateTime1.Ticks); TimeSpan ts2 = new TimeSpan(DateTime2.Ticks); TimeSpan ts = ts1.Subtract(ts2).Duration(); //计算时间差 DateDiff = ts.Days.ToString() + "天" + ts.Hours.ToString() + "小时" + ts.Minutes.ToString() + "分钟" + ts.Seconds.ToString() + "秒"; timeThrough = Convert.ToDouble (ts.Days.ToString ()) * 24 + Convert.ToDouble (ts.Hours.ToString()) + Convert.ToDouble (ts.Minutes.ToString()) / 60 +Convert.ToDouble ( ts.Seconds.ToString() )/ 3600; lbxList.Items.Add("通过时间:" + DateDiff); //利用简单工厂模式根据下拉选择框,生成相应的对象。 BarCharge barCharge = CashFactory.createCashAccept(cbxTimeType.SelectedItem.ToString()); double money = 0d; money = barCharge.acceptCash(Convert.ToDouble(timeThrough) * 2); lbxList.Items.Add("需要支付上网的费用:" + money +"元");//通过多态,可以得到收取费用的结果 } } //创建一个网吧现金收取的抽象类 abstract class BarCharge { public abstract double acceptCash(double money);//收取现金,参数为原价,返回为当前价 } //网吧的收费机制分为白天和晚上收费两种情况 class Day : BarCharge //白天收费情况 { public override double acceptCash( double money) { return money ;//白天收费,返回钱数 } } class Night : BarCharge //晚上收费情况 { private double moneyRebate = 1d; //晚上收费,初始化必须要输入收费条件,晚上优惠率 public Night(string moneyRebate) { this.moneyRebate = double.Parse(moneyRebate); } //晚上收费=晚上收费*优惠率 public override double acceptCash(double money) { return money * moneyRebate ; } } //现金收费工厂类 class CashFactory { public static BarCharge createCashAccept(string type) { BarCharge bc = null; switch (type)//根据条件返回白天和晚上收费情况 { case "白天": bc = new Day();//实例化对象 break; case "晚上": bc = new Night("0.8");//给出必要参数 break; } return bc; } } }运行结果:
简单工厂解决了对象的创建问题,免除了直接创建对象的步骤,实现了责任的分割。
但是由于工厂本身包括了所有的收费方式,每次维护或者扩展收费方式都要改动这个工厂,以至于代码需要重新编译部署,这样违背了开放-封闭原则。
四、感受
走别人的的路,不如自己 to do (不如的意思是更)。先敲书上的例子,第一遍也许不懂,第二遍就清晰很多,第三遍就觉得自己能写点东西出来。不要总是觉得自己看不懂,学不好,只有先学了才能更好。没有之前的8个馒头,就没有第9个馒头的饱(好撑啊~~)。