`

设计模式学习笔记六:.NET反射工厂

    博客分类:
  • .Net
阅读更多

1. 简述

    通过前面的学习,我们以传统的方式实现了简单工厂,工厂方法和抽象工厂,但是有些场合下如此处理,代码会变得冗余并且难以维护。假设我们要创建交通工具。可以是汽车,火车,轮船等,其结构如下:

 

     我们可以采用简单工厂,通过参数指示创建所需要的对象类型。如果要增加子类,例如卡车和轿车,则必须增加参数和相应的代码。如果子类层次过多,则会是程序变得很难维护。 
    但我们可以采用工厂方法模式来实现,即定义一个产生交通工具的接口,然后在子类中实现创建具体子类。代码如下: 

 

public interface ICreateVehicle
    {
         Vehicle CreateCehicle();
    }

 public abstract class Vehicle
    {

    }

public class Car:Vehicle
    {
        public Car()
        {
            Console.WriteLine("创建了一个Car");
        }
    }

public class Boat:Vehicle 
    {
        public Boat()
        {
            Console.WriteLine("创建了一个Boat");
        }
    }

    public class CreateCar:ICreateVehicle
    {
        ICreateVehicle 成员#region ICreateVehicle 成员

        public  Vehicle CreateCehicle()
        {
            Vehicle vehicle=new Car();
            return vehicle;
        }

        #endregion
    }

    public class CreateBoat:ICreateVehicle
    {
        ICreateVehicle 成员#region ICreateVehicle 成员

        public Vehicle CreateCehicle()
        {
            Vehicle vehicle = new Boat();
            Console.WriteLine("Car");
            return vehicle;
        }

        #endregion
    }

 

 这就是工厂方法。如果希望增加新的交通工具,不仅需要实现交通工具接口,还需要实现生产交通工具的工厂方法。

    显然我们需要几十种交通工具,则需要几十个具体的工厂。而这些类的区别仅仅是返回相对应的类的实例,所以位维护带来了很大的麻烦。如果需要在接口中增加一个带参数的方法,则所有的子类都需要修改。
在这种场合下,采用抽象工厂与工厂方法没有区别,因为这里并不涉及产品线,抽象工厂并不能解决其中的问题,如果每种交通工具都要有对应的车站,则要使用抽象工厂,但是将会跟复杂。

有没有可能将需要创建类的类型传递到工厂方法中,由工厂方法根据类型返回相应的实例?解决这个问题的关键是需要动态的决定需要创建的类,这不是设计模式能解决的问题,属于软件平台的功能范畴。.NET可以提供反射技术。

我们先看通过反射技术实现的简化的工厂,代码如下:

 public class CreateVehicleByType:ICreateVehicle
    {

        ICreateVehicle 成员#region ICreateVehicle 成员

        private Type VehicleTYpe;

        public CreateVehicleByType(string strType)
        {
            Type t = Type.GetType(strType);

            VehicleTYpe = t;
        }
        public  Vehicle CreateCehicle()
        {
            ConstructorInfo  objConstrutor = VehicleTYpe.GetConstructor(System.Type.EmptyTypes);
            Vehicle c = (Vehicle)objConstrutor.Invoke(null);
            return c;
        }

        #endregion

       
    }

 

 

 在使用是,只要在创建时带入需要创建的类的类型:

static void Main(string[] args)
        {

            string strType = "Car";

            Vehicle v;
            ICreateVehicle f = null;

            if (strType == "Car")
            {
                f = new CreateVehicleByType("FactoryVehicle.Car");

            }
            else if (strType == "Boat")
            {
                f = new CreateVehicleByType("Boat");
            }
            v = f.CreateCehicle();
            Console.ReadLine();

        }

 

 

 通过反射技术,我们将很多的具体的工厂类简化为一个类,并且新增加类型时不需要新的工厂类,这样我们得到简化的工厂,可以称其为“反射工厂”。

2.实例

         先来看看,大话设计模式中的利用反射加抽象工厂的数据访问程序。先来看看反射技术的基本格式:

Assembly.Load(“程序集名称”).CreateInstance(“命名空间.类名称”);

只要在程序顶端写上using System.Reflection来引用Reflection,就可以采用反射工厂来克服抽象工厂模式的先天不足。下面我们来看通过反射技术实现不同数据库的访问程序.

         先来看结构图:

 

 

 

DataAccess类,用反射技术,取代了抽象工厂中的IFactory,SqlServerFactoryAccessFactory
    
具体代码:

 

public 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; }
        }
    }

    public 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; }
        }
    }

    public interface IUser
    {
        void Insert(User user);

        User GetUser(int id);
    }

    public class SqlserverUser : IUser
    {
        public void Insert(User user)
        {
            Console.WriteLine("在Sqlserver中给User表增加一条记录");
        }

        public User GetUser(int id)
        {
            Console.WriteLine("在Sqlserver中根据ID得到User表一条记录");
            return null;
        }
    }

    public class AccessUser : IUser
    {
        public void Insert(User user)
        {
            Console.WriteLine("在Access中给User表增加一条记录");
        }

        public User GetUser(int id)
        {
            Console.WriteLine("在Access中根据ID得到User表一条记录");
            return null;
        }
    }

    public interface IDepartment
    {
        void Insert(Department department);

        Department GetDepartment(int id);
    }

    public class SqlserverDepartment : IDepartment
    {
        public void Insert(Department department)
        {
            Console.WriteLine("在Sqlserver中给Department表增加一条记录");
        }

        public Department GetDepartment(int id)
        {
            Console.WriteLine("在Sqlserver中根据ID得到Department表一条记录");
            return null;
        }
    }

    public class AccessDepartment : IDepartment
    {
        public void Insert(Department department)
        {
            Console.WriteLine("在Access中给Department表增加一条记录");
        }

        public Department GetDepartment(int id)
        {
            Console.WriteLine("在Access中根据ID得到Department表一条记录");
            return null;
        }
    }

    public class DataAccess
    {
        private static readonly string AssemblyName = "抽象工厂模式";
        private static readonly string db = "Sqlserver";
        //private static readonly string db = "Access";

        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);
        }
    }

  

调用代码: 

 User user = new User();
            Department dept = new Department();

            IUser iu = DataAccess.CreateUser();

            iu.Insert(user);
            iu.GetUser(1);

            IDepartment id = DataAccess.CreateDepartment();
            id.Insert(dept);
            id.GetDepartment(1);

            Console.Read();
        }

 

 现在我们要增加Oracle数据访问,相关类的增加是不可避免的,这点是无论我们用什么方法都解决不了的,这是扩展,依照开发-封闭原则,对于扩展,我们开放,但对与修改我们关闭。就现在的代码中,我们要换Oracle很容易,只需将db=”Sqlserver”换成db=”Oracle”
    
现在我们需要增加Product,只需增加三个与Product相关的类,再修改一下DataAccess,在其中增加一个创建Product的方法就可以了。
    
现在我们要更换数据访问程序是,我们还需要修改程序,重新编译,我们可以利用配置文件来解决这个问题,首先要在我们的项目中添加config文件,内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <add key="DB" value="Sqlserver"/>
    </appSettings>
</configuration>

 

 

 再在项目中引用System.configuration,并在程序头增加using System.configuration;, 然后修改DataAccess类的字段db的赋值代码:

class DataAccess
    {
        private static readonly string AssemblyName = "抽象工厂模式";
        private static readonly string db = ConfigurationManager.AppSettings["DB"];
        
        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);
        }
    }

 

 

 3.总结

         使用反射工厂的优点是极大的减少了工厂类的数量,降低了代码的冗余,并且系统更容易扩展,增加新类型后,不需要修改工厂类。

         使用反射工厂的代价是工厂与产品之间的依赖关系不明显,由于动态绑定,因此理论上可以用一个工厂完成很多类型的实例化,从而使得代码不容易理解。另外就是增加了测试难度,因为创建是动态完成的。

         采用反射技术创建的反射工厂可以使系统更灵活,使工厂和产品之间的依赖关系更小。在.NET的项目中大量的使用了反射工厂取代的传统的工厂。

 

 

分享到:
评论

相关推荐

    .Net 面向对象及设计模式总结

    1. UML类图:这是设计模式学习的基础,它用图形方式描绘类与类之间的关系,如继承、关联、聚合等,帮助我们更好地理解和设计系统架构。 2. 反射:.NET反射工厂模式利用反射机制动态创建对象,提供了在运行时获取...

    .net面试笔记六份及题库

    《.NET面试笔记六份及题库》是一个针对求职者准备.NET相关面试的重要资源集合,涵盖了.NET技术栈的多个方面,旨在帮助应聘者系统性地复习和掌握面试中可能遇到的关键知识点。以下是对这些笔记和题库的详细解读: 1....

    Java和.net的笔记

    "C#、[2].Net经典面试题目及答案+.doc"文档可能包含了C#语法、.NET框架、设计模式、面向服务架构(SOA)等相关面试问题及其解答,对于准备.NET相关面试非常有帮助。 至于"Java面试的32个要点.txt",这可能列出了...

    中美 IT 培训 C# Asp.net 全套笔记1

    C# 基本语法、面向对象的思想、数据结构和算法以及设计模式(120课时) 详细介绍.Net Framework、C# 基本语法、编程规范和编程技巧、面向对象的认识问题和分析问题的思想、以及数据结构和常用算法,学习单件模式、...

    中美 IT 培训 C# Asp.net 笔记3

    C# 基本语法、面向对象的思想、数据结构和算法以及设计模式(120课时) 详细介绍.Net Framework、C# 基本语法、编程规范和编程技巧、面向对象的认识问题和分析问题的思想、以及数据结构和常用算法,学习单件模式、...

    中美 IT 培训 C# Asp.net 笔记2

    C# 基本语法、面向对象的思想、数据结构和算法以及设计模式(120课时) 详细介绍.Net Framework、C# 基本语法、编程规范和编程技巧、面向对象的认识问题和分析问题的思想、以及数据结构和常用算法,学习单件模式、...

    net学习笔记及其他代码应用

    11.用.net做B/S结构的系统,您是用几层结构来开发,每一层之间的关系以及为什么要这样分层? 答:一般为3层 数据访问层,业务层,表示层。 数据访问层对数据库进行增删查改。 业务层一般分为二层,业务表观层...

    C#-学习笔记

    在深入探讨"C#高级编程"的学习笔记之前,我们先来理解一下C#这门语言的基础。C#(读作"C sharp")是由微软公司开发的一种面向对象的编程语言,主要用于构建Windows应用程序、Web应用以及移动应用。它在.NET框架或...

    C#笔试题大全,C#面试集合包括了,.net程序员面试题基础概念,面试题及答案,学习笔记,基本语法和问题集锦,是C#爱好者不可多得的学习资料。

    - 常见的设计模式如单例模式、工厂模式、观察者模式等在面试中常被提及。 10. **面试题示例** - **生命周期管理**:了解对象何时创建和销毁,以及垃圾回收机制。 - **访问修饰符**:解释public、private、...

    C#反射基础学习

    这篇学习笔记将带你深入了解C#反射的基础知识,帮助你掌握这一关键技能。 1. **程序集(Assembly)**:程序集是.NET应用程序的基本部署和版本控制单位,包含了元数据和IL(中间语言)代码。你可以通过`System....

    学习笔记 java\CoreJava笔记\CoreJava_day15

    - 设计模式是解决软件设计中常见问题的模板,如单例模式、工厂模式、观察者模式等。它们是经验的总结,提高了代码的可读性和可维护性。 9. **泛型**: - 泛型引入了类型参数,使得容器可以保存特定类型的对象,...

    Java学习笔记(必看经典)

    设计模式是解决常见编程问题的通用解决方案,反射允许程序在运行时动态访问类和对象的信息,注解为编译器和运行时提供了元数据,JVM内存模型则涉及到对象的生命周期和内存分配。 总之,“Java学习笔记(必看经典)”...

    java笔记图解6

    Java中常见的设计模式如工厂模式、单例模式、观察者模式等,是提高代码可读性和可维护性的有力工具。 10. **JVM优化**:理解Java虚拟机(JVM)的工作原理有助于进行性能调优。这包括堆内存管理、垃圾回收策略、JVM...

    java笔记图解13

    7. **设计模式**:Java笔记中可能也会涉及设计模式,如单例模式、工厂模式、观察者模式等,这些都是软件设计的最佳实践,提高了代码的可重用性和可维护性。 以上内容仅为Java笔记图解13可能涉及的部分主题,实际...

    C#自己总结的原码带注释

    14. **设计模式**:学习常见的设计模式,如工厂模式、单例模式、观察者模式等,有助于提升代码的可维护性和可扩展性。 15. **.NET框架与.NET Core**:了解.NET框架的结构和.NET Core的优势,知道如何选择合适的平台...

    值类型与引用类型理论内容.part01.rar

    ASP.NET培训资料(笔记版)(AJAX,C#,JavaScript,SQL) 详细的资料 三个月的课程录像+资料笔记(花了一万六千块的培训资料超值【19G的经典内容】 认真学习后包你能成为优秀的.net程序员 &lt;br&gt;(注明:不是...

    值类型与引用类型理论内容.part05.rar

    C#,JavaScript,SQL) &lt;br&gt;我将不定期发布,直至所有课程完毕 &lt;br&gt;详细的资料 三个月的课程录像+资料笔记(花了一万六千块的培训资料超值【19G的经典内容】 认真学习后包你能成为优秀的.net程序员 ...

    C#技巧文章

    以上仅是C#编程中的一部分核心概念,实际应用中还包括更多高级特性和最佳实践,如反射、委托的使用、设计模式、单元测试等。通过深入学习和实践,你可以逐步成为一名熟练的C#开发者。在"C#技术笔记"中,你将找到更多...

    c#学习资料和笔记收录

    以上只是C#学习的一部分关键知识点,随着深入学习,你还会接触到更多高级特性,如元数据、反射、委托链、异步流、模式匹配等。C#是一个持续演进的语言,每年的版本更新都会带来新的特性和改进,如C# 9.0引入的顶级...

    java从新开始

    9. **设计模式**:介绍常见的设计模式,如单例、工厂、观察者等,提升代码的可复用性和可维护性。 10. **Java EE**:如果资源深入,可能会涉及Java企业版相关的Web开发知识,如Servlet、JSP、MVC框架(如Spring MVC...

Global site tag (gtag.js) - Google Analytics