复用离不开反射和IOC
现在就让我们一起来看一下什么是多态以及如何实现多态。
多态就是不同的对象收到相同的消息时会产生不同的行为。同一个类在不同的场合下表现出不同的行为特征。
多态的作用:把不同的子类对象当做父类来看,可以屏蔽不同的子类对象之间的差异,写出通用的代码,做出通用的编程,增加程序的灵活性和可扩展性,以适应需求的不断变化。
如何实现多态呢?
首先实现多态的条件就是继承(或实现接口)。实现多态的方式可以有以下三种方式:
1、父类成员用virtual关键字修饰,子类可以重写父类成员(此处所指的成员均为子类可以继承的成员)
2、父类成员用abstract关键字修饰,子类可以重写父类的成员而且必须重写(最终)。
3、实现接口,子类可以实现接口中定义的方法而且必须实现。
一、使用virtual实现多态
用virtual修饰的方法称为虚方法。
1、当父类有方法需要让子类重写时,则可以将此方法标记为virtual。
2、虚方法在父类中必须要给出实现,哪怕是空实现。
3、子类可以重写父类的虚方法,也可以不重写。
下面我们就来看一个小例子:
1 static void Main( string [] args)
2 {
3 object str = " 你好 " ;
4 object person = new Person() { Name= " 张三 " };
5 Console.WriteLine(str.ToString()); // 此处输出什么?
6 Console.WriteLine(person.ToString()); // 此处输出什么?
7 Console.ReadKey();
8 }
9
10 public class Person
11 {
12 public string Name
13 {
14 get ;
15 set ;
16 }
17 }
聪明的你是不是已经知道了输出的结果呢?没错,第一行输出“你好”,第二行输出“命名空间.Person”,其中的命名空间据你的项目而定,同样都是object对象,为什么会出现这种情况呢?要解决这个问题,我们先得了解一下ToString()方法。
ToString()是object类定义的一个虚方法,其实现的功能为把当前对象的类型装换为字符串输出。那么第一行为什么没有输出对象的类型呢?以为string类重写了ToString()方法,把当前对象输出了(即把string对象本身输出)。由于Person类没有重写ToString()方法,所以输出的是当前对象的类型。
下面我们把Person类的代码稍稍改动一下。
public class Person
{
public string Name
{
get ;
set ;
}
public override string ToString()
{
return this .Name;
}
}
此时第二行就会输出“张三”。
二、使用abstract实现多态
先来看一下有关抽象类的相关概念:
1、abstract关键字不光可以修饰类成员,还可以修饰类。被abstract修饰的类称为抽象类,被abstract修饰的方法称为抽象方法。
2、抽象类不能被实例化,如果要想实例化,则必须有子类继承他,并且抽象类变量只能指向实现了他中的所有抽象成员的子类对象。
3、抽象类的子类如果没有实现他的抽象方法,或者只是实现了一部分,则这个类也必须是抽象类。
4、如果一个类中包含抽象方法,则这个类必须声明为抽象类。反之,抽象类中不一顶含有抽象方法。
5、抽象方法必须不能给出任何实现。
6、抽象类既可以包含抽象成员,又可以包含具体代码成员。
7、抽象类不能用static或sealed修饰。抽象方法不能用static或private修饰。
8、抽象类中有构造函数,而且可以重载。
说了好多,我都有点凌乱了,哈哈……
记得曾经有人和我争论一个问题,说抽象类可以不被子类继承(很纠结的问题),这句话百分之百是对的,但是我们在项目中定义一个抽象类,而不用子类去继承他,那么它的存在还有什么意义呢?既然我们定义了抽象类,说明我们一定要用他,既然要用它就必须要有子类继承他(因为他本身不能被实例化)。(个人观点,有些偏激)
下面我们来做一个抽象类的小例子:
“橡皮鸭子(RubberDuck)、真实的鸭子(RealDuck)。两个鸭子都会游泳,而橡皮鸭子和真实的鸭子都会叫,只是叫声不一样,橡皮鸭子“唧唧”叫,真实地鸭子“嘎嘎”叫”
public abstract class Duck
{
public string Name
{
get ;
set ;
}
public void Swim()
{
Console.WriteLine( " 我是{0},I can swimming! " , this .Name);
}
public abstract void Speek();
}
public class RubberDuck:Duck
{
public RubberDuck( string name)
{
this .Name = name;
}
public override void Speek()
{
Console.WriteLine( " 唧唧... " );
}
}
public class RealDuck : Duck
{
public RealDuck( string name)
{
this .Name = name;
}
public override void Speek()
{
Console.WriteLine( " 嘎嘎... " );
}
}
static void Main( string [] args)
{
Duck duck1 = new RubberDuck( " RubberDuck " );
Duck duck2 = new RealDuck( " RealDuck " );
duck1.Swim();
duck1.Speek();
duck2.Swim();
duck2.Speek();
Console.ReadKey();
}
至于输出结果,大家在脑子中输出一下吧。。。
三、使用接口实现多态
神马是接口?
接口就是一种规范,一种协议,约定好遵守某种协议就可以写出通用的代码。
1、接口中定义了若干个具有各自功能的方法,只是表示一种能力,并没有具体实现。
2、接口中的成员不能有访问修饰符,默认public。
3、接口中可以有属性,方法,索引器,事件等(归根结底都是方法),但是不能有字段(可以有静态)。
4、实现接口的子类必须实现该接口的全部成员。(直接子类)
5、一个类可以同时实现多个接口,接口也可以继承接口。
6、接口不能被实例化。
7、如果继承接口的类不想全部实现接口中的成员,则可以把这个类声明为抽象类,把不实现的方法声明为抽象方法。
8、如果一个类同时继承了类和实现了接口,则必须把类放在前面。
是不是又凌乱了呢?好吧,先说这么多吧。
有时候我们总是觉得既然有了抽象类,还要接口做什么呢?其实接口是有他的存在意义的。比如我们看下面的例子:
“一架直升飞机和一只麻雀都会飞,但是一架直升飞机属于飞机类,一只麻雀属于鸟类,飞机不具备鸟类的共有属性,同理,鸟类也不具有飞机类的共有特性,因此他们不能抽象一个共有的父类(否则从他们的父类派生的子类就会同时具备飞机和鸟类的全部特性,这会造成子类冗余)。那么在这种情况下,我们要想对”飞“这个能力实现多态,该怎么办呢?对,用接口。
public class Plane
{
public string Name
{
set ;
get ;
}
public void LoadPeople()
{
Console.WriteLine( " 我可以载人 " );
}
}
public class Bird
{
public string Name
{
set ;
get ;
}
public void Raise()
{
Console.WriteLine( " 我可以繁殖后代 " );
}
}
public interface IFlyable
{
void Fly();
}
public class VertiPlane:Plane,IFlyable
{
public void Fly()
{
Console.WriteLine( " 我是{0},I can Flying! " , this .Name);
}
}
public class Sparrow : Plane, IFlyable
{
public void Fly()
{
Console.WriteLine( " 我是{0},I can Flying! " , this .Name);
}
}
static void Main( string [] args)
{
IFlyable plane = new VertiPlane() { Name= " 直升飞机 " };
IFlyable bird = new Sparrow { Name = " 麻雀 " };
plane.Fly();
bird.Fly();
Console.ReadKey();
}
此时如果我们要用这两个对象的其他属性怎么办呢?可以显示转换为想要的类型(前提是他指向的对象必须是将要转换的类型)
从本文标题中可以看出,主要说的是反射技术和控制反转(IOC)技术,本文主要先介绍一下我对这两种技术的理解及它们的优缺点,最后再用实例来说一下使用方法。
反射:可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。这里,它最重要的是“动态性”,即根据条件动态创建“指定类型”的“实例”。
1 // Using GetType to obtain type information: 2 int i = 42 ; 3 System.Type type = i.GetType(); 4 System.Console.WriteLine(type);
结果是:
System.Int32
本示例使用静态方法 GetType( Object 基类派生的所有类型都继承该方法) 获取变量类型的简单反射实例
1 // Using Reflection to get information from an Assembly: 2 System.Reflection.Assembly o = System.Reflection.Assembly.Load( " mscorlib.dll " ); 3 System.Console.WriteLine(o.GetName());
结果是:
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
本示例使用反射获取已加载的程序集的完整名称
反射一般用在以下情况中:
需要访问程序元数据的属性。linq to sql 中使用很多
执行后期绑定,访问在运行时创建的类型的方法。与工厂模式一起使用,根据配置文件中的类型来动态建立实例
IOC:(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题。 控制反转还有一个名字叫做依赖注入(Dependency Injection)。简称DI。实现IOC的架构有很多如:Avalon 、Spring、JBoss及Unity等。
理解IOC:可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的,然后利用Java 的“反射”编程,根据XML中给出的类名生成相应的对象。
实现非常简单,根据容易名称去创建对象即可
1 /// <summary>
2 /// The static factory of container
3 /// </summary>
4 public sealed class ContainerManager
5 {
6 /// <summary>
7 /// Creates the specified container instance .
8 /// </summary>
9 /// <param name="containerName"> Name of the container. </param>
10 /// <returns></returns>
11 public static IContainerContext GetContainer( string containerName)
12 {
13 return new UnityContainerContext(containerName);
14 }
15 }
以下是在实际项目中的使用,IOC架构是用Unity,它的基础代码是:
1 /// <summary>
2 /// The specific container context for Unity
3 /// </summary>
4 public class UnityContainerContext : ContainerContextBase
5 {
6 #region Fields
7
8 /// <summary>
9 /// The lock used for synchronous
10 /// </summary>
11 private static readonly object _synlock = new object ();
12
13 #endregion
14
15 #region Constructor
16
17 /// <summary>
18 /// Initializes a new instance of the <see cref="UnityContainerContext"/> class.
19 /// </summary>
20 /// <param name="name"> The name. </param>
21 public UnityContainerContext( string name)
22 : base (name)
23 {
24 }
25
26 #endregion
27
28 #region Properties
29
30 /// <summary>
31 /// Gets the current context.
32 /// </summary>
33 /// <value> The current context. </value>
34 private HttpContext CurrentContext
35 {
36 get
37 {
38 HttpContext context = HttpContext.Current;
39 if (context == null )
40 {
41 throw new Exception( " The current httpcontext is null " );
42 }
43 return context;
44 }
45 }
46
47 #endregion
48
49 #region Override Methods
50
51 /// <summary>
52 /// Initializes container.
53 /// </summary>
54 public override void Initialize()
55 {
56 OnBeforeInitialized( new ContainerEventArgs( this , ContainerType.Unity));
57
58 if (CurrentContext.Application[Name] == null )
59 {
60 lock (_synlock)
61 {
62 if (CurrentContext.Application[Name] == null )
63 {
64 IUnityContainer currentContainer = new UnityContainer();
65 UnityConfigurationSection section = ConfigurationManager.GetSection( " unity " ) as UnityConfigurationSection;
66 section.Containers[Name].Configure(currentContainer);
67 CurrentContext.Application[Name] = currentContainer;
68 }
69 }
70 }
71
72 OnAfterInitialized( new ContainerEventArgs( this , ContainerType.Unity));
73 }
74
75 /// <summary>
76 /// Resolves this instance.
77 /// </summary>
78 /// <typeparam name="T"> Parameter type. </typeparam>
79 /// <returns></returns>
80 public override T Resolve<T> ()
81 {
82 try
83 {
84 Initialize();
85
86 IUnityContainer currentContainer = CurrentContext.Application[Name] as IUnityContainer;
87 return currentContainer.Resolve<T> ();
88 }
89 catch (Exception ex)
90 {
91 OnResolveFailed( new ContainerFailedEventArgs( this , ContainerType.Unity, ex));
92 return default (T);
93 }
94 }
95
96 /// <summary>
97 /// Tears down.
98 /// </summary>
99 public override void TearDown()
100 {
101 OnBeforeTearDown( new ContainerEventArgs( this , ContainerType.Unity));
102
103 CurrentContext.Application[Name] = null ;
104
105 OnAfterTearDown( new ContainerEventArgs( this , ContainerType.Unity));
106 }
107
108 #endregion
109
110 }
在项目中通过unity来创建对象的代码是:
1 /// <summary>
2 /// 数据层实体的个性操作对象
3 /// </summary>
4 /// <typeparam name="TEntity"></typeparam>
5 /// <returns></returns>
6 protected TEntity LoadRepositoryEntity<TEntity> ()
7 {
8 IContainerContext container = ContainerManager.GetContainer( " repositoryContainer " );
9 return container.Resolve<TEntity> ();
10 }
这样,在BLL层调用DAL层对象时,可以通过LoadRepositoryEntity泛型方法来实现。
分类: 系统架构
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息