namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Operation oper;
oper = Operatio nFactory.createOperation("/");
oper.NumberA = 1;
oper.NumberB = 0;
double result = oper.GetResult();
Console.WriteLine(result);
Console.ReadKey();
}
}
/// <summary>
/// 运算父类
/// </summary>
public class Operation
{
private double _numberA = 0;
private double _numberB = 0;
public double NumberA
{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB
{
get { return _numberB; }
set { _numberB = value; }
}
public virtual double GetResult()
{
double result = 0;
return result;
}
}
///加减乘除类
class OperationAdd : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA + NumberB;
return result;
}
}
class OperationSub : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA - NumberB;
return result;
}
}
class OperationMul : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA * NumberB;
return result;
}
}
class OperationDiv : Operation
{
public override double GetResult()
{
double result = 0;
if (NumberB == 0)
{
throw new Exception("除数不能为0.");
}
result = NumberA / NumberB;
return result;
}
}
/// <summary>
/// 工厂起到了纽带的作用,用户输入的两个数和运算符是材料,运算类是工厂里的车间,工厂就是根据用户的
/// 需求配置适当的生产线进行生产
/// </summary>
public class OperationFactory
{
public static Operation createOperation(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;
}
}
}
简单工厂很好的利用了封装,继承和多态。把几个算法进行了封装并且继承了接口运算类;工厂里使用了虚方法,在主函数中用到了多态。
最大优点是工厂根据客户端的条件动态实例化类。
较好的实现了软件的可维护性,可复用性和灵活性。如果要对某个算法,比如加法进行修改,只需要修改加法的类就OK了,不用涉及到其他的类,降低了类之间的耦合性。但是扩展性差。如果要加一个乘方的算法,不仅要加一个乘方的类还要更改客户端的代码,违反了开闭原则。
有缺点就有解决的方法,所以简单工厂的升级版工厂方法就应运而生了。
`namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
IFactory operFactory = new DivFactory();
Operation oper = operFactory.CreateOperation();
oper.NumberA = 10;
oper.NumberB = 0;
double result = oper.GetResult();
Console.WriteLine(result);
Console.ReadKey();
}
}
///
/// 运算类
///
public class Operation
{
private double _numberA = 0;
private double _numberB = 0;
public double NumberA
{
get { return _numberA; }
set { _numberA = value; }
}
public double NumberB
{
get { return _numberB; }
set { _numberB = value; }
}
public virtual double GetResult()
{
double result = 0;
return result;
}
}
///加减乘数类
class OperationAdd:Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA + NumberB;
return result;
}
}
class OperationSub : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA - NumberB;
return result;
}
}
class OperationMul : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA * NumberB;
return result;
}
}
class OperationDiv:Operation
{
public override double GetResult()
{
double result = 0;
if (NumberB == 0)
throw new Exception("除数不能为0.");
result = NumberA / NumberB;
return result;
}
}
/// <summary>
/// 定义一个工厂的接口
/// </summary>
interface IFactory
{
Operation CreateOperation();
}
///
/// 加法工厂
///
class AddFactory:IFactory
{
public Operation CreateOperation()
{
return new OperationAdd();
}
}
///
/// 减法工厂
///
class SubFactory:IFactory
{
public Operation CreateOperation()
{
return new OperationSub();
}
}
///
/// 乘法工厂
///
class MulFactory : IFactory
{
public Operation CreateOperation()
{
return new OperationMul();
}
}
///
/// 除法工厂
///
class DivFactory:IFactory
{
public Operation CreateOperation()
{
return new OperationDiv();
}
}
}
`
和简单工厂的类图相比,工厂方法最大的特点就是抽象出了一个工厂类的接口,而每个算法类都有对应的工厂。
简单工厂中需要再客户端传入运算符,然后算法工厂根据符号实例对应的类;而工厂方法是通过工厂类这个接口找到要用的具体工厂,再让具体工厂去实例化它对应的类。
逻辑判断有简单工厂里的工厂类转移到了工厂方法里的客户端,所以在客户端就要清楚需要使用哪一个具体工厂。
工厂方法比简单工厂方法先进的地方就在于工厂方法保证了扩展性,符合了开闭原则。如果需要添加新的算法,只需添加新的算法类和对应的工厂。
工厂方法中每一类都有对应的工厂,就如我要生产上衣,裤子,鞋这3样产品,我首先要有生产他们的方法即类,然后需要上衣工厂,裤子工厂,鞋厂3个工厂。但是我现在要对生产更加细化,我要生产学生的校服,老师的工作服,餐厅服务员的工作服,学生,老师,餐厅服务员每套服装都需要上衣,裤子和鞋,哪该怎么办?现在工厂方法就显得力不从心了,总不能学生上衣一个工厂,学生裤子一个工厂,老师上衣一个工厂这样弄九个工厂吧。这还是少的,3对3,如果服装里再加上帽子,袜子等,分类里再加上正装,晚礼服等。。就这样抽象工厂横空出世了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace 抽象工厂
{
class Program
{
static void Main(string[] args)
{
User user = new User();
Department dept = new Department ();
IFactory factory = new AccessFactory();
IUser iu = factory .createUser();
iu .Insert (user);
iu.GetUser(1);
IDepartment id = factory.createDepartment ();
id.Insert(dept );
id.GetDepartment(1);
Console.Read();
//反射
//return (IUser)Assembly.Load("抽象工厂").CreateInstance ("抽象工厂.SqlserverUser");
}
}
/// <summary>
/// User 类
/// </summary>
class User
{
private int _id;
public int ID
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
/// <summary>
/// IUser 接口, 用于客户端访问,解除与具体数据库访问的耦合
/// </summary>
interface IUser
{
void Insert (User user);
User GetUser(int id);
}
/// <summary>
/// SqlserverUser 类就,用于访问SQL Server的User.
/// </summary>
class SqlserverUser:IUser
{
public void Insert(User user)
{
Console.WriteLine("在SQL中给User表增加一条记录");
}
public User GetUser(int id)
{
Console.WriteLine("在SQL中根据ID 得到User表的一条记录");
return null;
}
}
/// <summary>
///用于访问access的User
/// </summary>
class AccessUser : IUser
{
public void Insert (User user)
{
Console.WriteLine("在access中给User表增加一条记录");
}
public User GetUser(int id)
{
Console.WriteLine ("在Access中根据ID得到User表一条记录");
return null;
}
/// <summary>
/// IFactory 接口,定义一个创建访问User表对象的抽象工厂接口
/// </summary>
interface IFactory
{
IUser CreateUser();
IDepartment CreateDepartment();
}
/// <summary>
/// SqlServerFactory类,实现IFactory接口,实例化SqlserverUser
/// </summary>
class SqlServerFactory:IFactory
{
public IUser CreateUser()
{
return new SqlserverUser();
}
public IDepartment CreateDepartment()
{
return new SqlserverDepartment();
}
}
class AccessFactory:IFactory
{
public IUser CreateUser()
{
return new AccessUser ();
}
public IDepartment CreateDepartment()
{
return new AccessDepartment ();
}
}
class Department
{
private int _id;
public int ID
{
get{return _id;}
set{_id = value;}
}
private string _deptName;
public string DeptName
{
get{return _deptName;}
set{_deptName = value; }
}
}
/// <summary>
/// 解除与具体数据库访问的耦合
/// </summary>
interface IDepartment
{
void Insert(IDepartment department);
Department GetDepartment(int id);
}
class SqlserverDepartment:IDepartment
{
public void Insert(Department department)
{
Console.WriteLine ("在SQL server中给department表增加一条记录 ");
}
public Department GetDepartment(int id)
{
Console.WriteLine ("在sql server 中根据id得到department表一条记录");
return null;
}
}
class AccessDepartment:IDepartment
{
public void Insert(Department department)
{
Console.WriteLine ("在access中给department增加一条记录");
}
public Department GetDepartment (int id)
{
Console.WriteLine ("在");
return null;
}
}
}
抽象工厂解决了工厂方法解决不了的多个产品,多种分类的问题。还以生产服装为例,要先建一个工厂的接口,它 定义了所有的抽象方法;然后建具体工厂,分别为:学生工厂,老师工厂,餐厅服务员工厂。比如学生工厂定义了学生上衣,裤子,鞋的尺寸,面料,样式,颜色等。然后就有3个接口:上衣,裤子,鞋。比如上衣就定义了要有两个袖子,领子等。这样如果我要老师的鞋,那我就找到老师工厂,再实现鞋这个接口,最后实例化老师鞋这个类,就能生产出我要的产品了。
抽象工厂优点:
1. 易于交换产品系列,由于具体工厂类,例如IFactory factory = new AccessFactory(),在一个应用中只需在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。
ps(能听懂和话):就是如果要生产晚礼服,只需要添加一个晚礼服的工厂,在客户端写成IFactory factory = new wanlifuFactory()就行了。
2. 它让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户端代码中。
ps(能听懂和话):这个优点工厂方法和抽象工厂都有,那就是客户端和类解耦,实例化类是在子类中进行的,而不像简单工厂一样在客户端根据符号就直接跟类打交道。
抽象工厂的缺点:
1.如果增加一个新的产品,需要增加新的类,还要修改工厂接口和具体工厂,违背了开闭原则。
2.如果需要多次调用类,就需要多次声明用的是哪个工厂,很麻烦。
Assembly.Load(“程序集名称”).CreateInstance(“命名空间.类名称”)
#region 反射
using System.Reflection;//引入反射
class DataAccess
{
private static readonly string AssemblyName= "抽象工厂";
private static readonly string db= "Sqlserver";
public static IUser CreateUser()
{
string className = AssemblyName + "." + db +"User";
return (IUser )Assembly.Load(AssemblyName).CreateInstance(className);
}
public static IDepartment CreateDepartment()
{
string className = AssemblyName + "."+ db + "Department";
return (IDepartment)Assembly.Load(AssemblyName ).CreateInstance(className );
}
}
#endregion
有困难就有解决的方法,抽象方法又是工厂接口,又是具体的工厂,扩展性和重用性可以实现但是很麻烦。其实程序的本质还是要找到那个含有具体方法的类,那才是干货。弄得这些接口啊什么也就是为了解耦。那为什么不直接找到那个类的地址。这就好像传值和传地址。要找小A不一定非得AA学校BB学院CC专业DD班E名字,直接一个学号就搞定了。
//反射
//return (IUser)Assembly.Load("抽象工厂").CreateInstance ("抽象工厂.SqlserverUser");
这个特别想做机房收费系统的时候每个窗体链接数据库的时候都要写的代码,现在想想那个就是反射。比起抽象工厂方便多了,把地址分为几段,比如我要用其他程序集的类只要换程序集的名称就行了,要想还数据库,只要把db的名字改了就行了。
最深的感悟有两条。
一、只有发现不了的问题,没有解决不了的问题。有问题就有解决方法。
简单工厂的扩展性差,所以工厂方法出现了;工厂方法解决不了多个产品,多个分类的问题,所以抽象工厂果断扛起了使命。但是抽象工厂太啰嗦,不方便,增加一个新类,要动的地方多,复用性也不强,所以有出来一个反射。这四个步骤是彼此关联不断升级的结果。
真的太佩服那些想到这些方法的人,人类的智慧啊,太伟大了。这就是不将就的精神!
二、类图很重要
看这本书没少惊讶,代码中的每一个类,接口等都是完全按照类图来的。之前画UML图的时候没有这么深的感受。我们眼里要看得见风景,心里要装的下万水千山。既要进的去又要出的来。精得了一域,更能谋得了全局。