1、工厂的引入
工厂的概念:生活中工厂是生产产品的,我们在软件中,工厂是创建“对象”的。
工厂的引入:在这里创建Teacher和Dean对象
App.config文件:这个是应用程序配置文件,你可以把程序配置的相关信息,都保存到这个文件中。
2、工厂的使用
【1】定义接口
【2】接口实现
除了Teacher和Dean这边还编写了一个用来代表OtherTeacher的类,和Teacher与Dean一样,它也继承自父类Person,实现了ITeach接口中的两个方法,Exam()
和 StudyCourse()
。
【3】编写工厂
第一、在App.config文件中,配置一个节点,用来保存可变的对象类型,当业务对象变更时只需要在配置文件中更改teacherClass节点的value而不需要对程序进行修改。
注意:节点名称严格区分大小写,不要写错;必须严格遵守xml的规范。
常见问题:System.TypeInitializationException:““xiketang.com4.ObjectFactory”
的类型初始值设定项引发异常。”
主要见到这种问题,就是读取配置文件的问题,怎么解决?
(1)看设置的节点,和读取的节点名称是否一致。
(2)App.config文件中节点 不要写错,如果你写成 是不行的。
(2)如果配置文件内容比较复杂,注意 不要放错位置。
第二、添加引用System.Configuration,同时添加命名空间:using System.Configuration
第三、编写对象工厂方法,返回具体接口对象。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Reflection;
namespace xiketang.com4
{
/// <summary>
/// 对象工厂(简单工厂,单一对象创建工厂)
/// </summary>
public class ObjectFactory
{
//从配置文件中读取相应节点中的内容
private static string teachClass = ConfigurationManager.AppSettings["teacheClass"].ToString();
private static string assName = ConfigurationManager.AppSettings["assName"].ToString();
/// <summary>
/// 工厂方法,返回具体的接口实现类对象
/// </summary>
/// <returns></returns>
public static ITeach CreateObject()
{
//思考,我们应该创建哪个接口实现类对象呢? Teacher Dean
//需求是变化的,我们应该把这种变化,变得可配置(就是不需要代码修改,只需要修改配置文件)
//if (teachClass == "Teacher")
//{
// return new Teacher { Name = "常老师" };
//}
//else if (teachClass == "Dean")
//{
// return new Dean { Name = "张主任" };
//}
//else if (teachClass == "OtherTeacher")
//{
// return new OtherTeacher { Name = "王老师" };
//}
//else
//{
// return new Teacher { Name = "张老师" };
//}
return (ITeach)Assembly.Load(assName).CreateInstance(teachClass);
}
}
}
第四、使用工厂方法返回对象,并调用对象所实现的接口方法。
3、工厂的好处
第一、对象的使用者,完全不用关心对象是如何创建的,完全解耦。
第二,用户需求变化的时候,通过配置文件轻松实现对象的替换。
问题:如果我们需要再次扩展更多的接口实现类对象,发现,工厂方法内部还得修改!这点还得需要优化。
解决对象在需求变化的时候,创建问题!使用反射!
4、反射技术的应用
程序集是应用程序的部署单元。常见的程序集?控制台程序生成的exe文件就是一个程序集;winform程序生成的exe文件也是程序集;类库生成的dll文件也是程序集!
关于对象创建:我们可以直接通过new的方式来创建,我们通过new是因为我们明确的知道要创建的对象类型。但是我们的需求是不同的对象类型!也就是通过new方式直接不可取!这时必须通过某种方式,找到要创建的对象类型。由此便引出了一个问题:从哪里找呢?怎么找呢?对于这个问题的回答是从程序集中找!通过程序集给我们提供的相关类里面的方法去找。
public void Test()
{
Assembly ass1 = Assembly.Load("InterfaceAndPolymorphism");
Assembly ass2 = Assembly.LoadFile(System.IO.Directory.GetCurrentDirectory() + "\\InterfaceAndPolymorphism.exe");
Assembly ass3 = Assembly.LoadFrom("InterfaceAndPolymorphism.exe");
//观察程序及给我们的信息
Type[] types = ass1.GetTypes();
foreach (var item in types)
{
//item.Name:类的名称
//item:类的完全限定名(命名空间+类名)
Console.WriteLine(item.Name+"\t\t"+item);
}
//我们从一个程序集中,能够找到所有的类型(类类型,接口类型、泛型类型....)
Console.WriteLine("===================================================");
//官方解释:获取程序集实例中具有指定名称的 System.Type 对象。
//老师解释:根据一个类的完全限定名字符串,从程序集中得到这个类的具体类型
Type teacherType = ass1.GetType("xiketang.com4.Teacher");//这个字符串严格区分大小写
//这个Type就是包括了一个类型的所有成员快照
//我们通过一个对象的类型,可以找到类的所有成员,比如我找Teacher的所有属性
PropertyInfo[] properties = teacherType.GetProperties();
foreach (var item in properties)
{
Console.WriteLine(item);
}
}
当我们知道一个程序集,就能找到所有的成员,想知道程序集里面有什么我们可以通过元数据查看程序集里边的命名空间、类名、类的各种成员(属性、方法等)的注释信息,具体用法参考上边的代码。
结论:通过控制台的exe文件,我们可以找到这个文件中所有的类和成员信息。通过反射改进简单工厂,让程序扩展性大大增强。如果我们程序需要的模块存在变化,只要事先规定好了接口,模块就可以任意替换。
public void Test()
{
Assembly ass1 = Assembly.Load("InterfaceAndPolymorphism");
Assembly ass2 = Assembly.LoadFile(System.IO.Directory.GetCurrentDirectory() + "\\InterfaceAndPolymorphism.exe");
Assembly ass3 = Assembly.LoadFrom("InterfaceAndPolymorphism.exe");
//官方解释:获取程序集实例中具有指定名称的 System.Type 对象。
//老师解释:根据一个类的完全限定名字符串,从程序集中得到这个类的具体类型
Type teacherType = ass1.GetType("xiketang.com4.Teacher");//这个字符串严格区分大小写
//这个Type就是包括了一个类型的所有成员快照,通过这个快照就可以进行对象的创建
Teacher teacher1 = (Teacher)Activator.CreateInstance(teacherType);
//使用指定类型的默认构造函数来创建该类型的实例
//public static object CreateInstance(Type type);
//通过反射创建对象
Teacher teacher2 = (Teacher)ass1.CreateInstance("xiketang.com4.Teacher");
//上面的内容合并写在一起
Teacher teacher3 = (Teacher)Assembly.Load("InterfaceAndPolymorphism").CreateInstance("xiketang.com4.Teacher");
}
5、参考链接
作者:晨岩
本站所有文章除特别声明外,均采用 BY-NC-SA 4.0 许可协议。转载请注明出处!
暂无评论内容