对象创建的依赖

对象创建的依赖

关于依赖的哲学,最典型的违反莫过于对象创建的依赖。自面向对象的大旗树立以来,对于对象创建话题的讨论就从未停止。不管是工厂模式还是依赖注入,其核心的思想就只有一个:如何更好地解耦对象创建的依赖关系。所以,在这一部分,我们就以对象创建为主线,来认识对于依赖关系的设计轨迹,分别论述一般的对象创建、工厂方式创建和依赖注入创建三种方式的实现、特点和区别。

1.典型的违反

一般而言,以new关键字进行对象创建,在.NET世界里是天经地义的事情。在本书7.1节“把new说透”中,就比较透彻地分析了new在对象创建时的作用和底层机制。对.NET程序员而言,以new进行对象创建已经是习以为常的事情,大部分情况下这种方式并没有任何问题。例如:

public abstract class Animal

    public abstract void Show();

}

 

public class Dog : Animal

{

    public override void Show()

    {

        Console.WriteLine("This is dog.");

    }

}

 

public class Cat : Animal

{

    public override void Show()

    {

        Console.WriteLine("This is cat.");

    }

}

 

public class NormalCreation

{

    public static void Main2()

    {

        Animal animal = new Dog();

    }

}

animal对象而言,大部分情况下具体的Dog类是相对稳定的,所以这种依赖很多时候是无害的。这也是我们习以为常的原因之一。

然而,诚如在本文开始对抽象和具体的概念进行分析的结论一样,依赖于具体很多时候并不能有效地保证其稳定性的状态。以本例而言,如果有新的BirdHorse加入到动物园中来,管理员基于现有体系的管理势必不能适应形式,因为所有创建而来的实例都是依赖于Dog的。所以,普遍的对象创建方式,实际上是对DIP原则的典型违反,高层Animal的创建依赖于低层的Dog,和普世的DIP基本原则是违背的。

因此,DIP并不是时时被OO所遵守,开发者要做的只是适度的把握。为了解决new方式创建对象的依赖违反问题,典型的解决思路是将创建的依赖由具体转移为抽象,通常情况下有两种方式来应对:工厂模式和依赖注入。

2.工厂模式

以工厂模式进行对象创建的方法,主要包括两种模式:抽象工厂模式和工厂方法模式,本文不想就二者的区别和意义展开细节讨论,如果有兴趣可以参阅GoF的《设计模式:可复用面向对象软件的基础》一书。

本文将视角拉回到WCFIChannelFactory和各种Channel的创建上,以此借用WCF架构中Channel Layer的设计思路,应用工厂模式进行对象创建的设计和扩展,来了解应用工厂模式进行对象创建依赖关系解除的实质和实现。

注意                                                                    

对于WCFChannel的概念可以参考相关的资料,在此你只需将其看成一个简单类型即可。

首先来了解一下Channel的创建过程:

public class FactoryCreation

{

    public static void Main()

    {

        EndpointAddress ea = new EndpointAddress("http://api.anytao.com /UserService");

        BasicHttpBinding binding = new BasicHttpBinding();

        IChannelFactory<IRequestChannel> facotry = binding.BuildChannelFactory<IRequestChannel>();

        facotry.Open();

        IRequestChannel channel = facotry.CreateChannel(ea);

        channel.Open();

        //Do something continue...

    }

}

在示例中,IRequestChannel实例通过IChannelFactory工厂来创建,因此关注工厂方式的创建焦点就着眼于IChannelFactoryIRequestChannel上。实质上,在WCF channel Layer中,Channel Factory是创建和管理Channel的工厂封装,通过一个个的Channel Factory来创建一个个对应的Channel实例,所有的Channel Factory必须继承自IChannelFactory,其定义为:

public interface IChannelFactory<TChannel> : IChannelFactory, ICommunicationObject

{

    TChannel CreateChannel(EndpointAddress to);

    TChannel CreateChannel(EndpointAddress to, Uri via);

}

通过类型参数TChannel来注册创建实例的类型信息,进而根据EndpointAddress信息来创建相应的对象实例。当然,WCF中的工厂模式应用,还有很多内容值得斟酌和学习。现有篇幅不可能实现完全类似的设计结构,借鉴于WCF的设计思路,对Animal实例的创建进行一点改造,实现基于泛型的工厂模式创建设计,首先定义一个对象创建的模板:

public interface IAnimalFacotry<TAnimal>

{

    TAnimal Create();

}

然后实现该模板的泛型工厂方法:

public class AnimalFacotry<TAnimalBase, TAnimal> : IAnimalFacotry<TAnimalBase> where TAnimal : TAnimalBase, new()

{

    public TAnimalBase Create()

    {

        return new TAnimal();

    }

}

其中类型参数TAnimalBase代表了高层类型,而TAnimal则代表了底层类型,其约定关系在where约束中有明确的定义,然后是一个基于对工厂方法的封装:

public class FacotryBuilder

{

    public static IAnimalFacotry<Animal> Build(string type)

    {

        if (type == "Dog")

        {

            return new AnimalFacotry<Animal, Dog>();

        }

        else if (type == "Cat")

        {

            return new AnimalFacotry<Animal, Cat>();

        }

 

        return null;

    }

}

最后,可以欣赏一下基于工厂方式的对象创建实现:

class Program

{

    static void Main(string[] args)

    {

        IAnimalFacotry<Animal> factory = FacotryBuilder.Build("Cat");

        Animal dog = factory.Create();

        dog.Show();

    }

}

你看,对象创建的依赖关系已经由new式的具体依赖转换为对于抽象和高层的依赖。在本例中,完全可以通过反射方式来消除if/else的运行时类型判定,从而彻底将这种依赖解除为可配置的灵活定制。这正是抽象工厂方式的伟大意义,其实在本例中完全可以将IAnimalFacotry扩展为IAnyFactory形式的灵活工厂,可以在类型参数中注册任何类型的TXXXBaseTXXX,从而实现功能更加强大的对象生成器,只不过需要更多的代码和扩展,读者可以就此进行自己的思考。

本文节选自《你必须知道的.NET(第2版)》一书

图书详细信息:http://www.cnblogs.com/broadview/archive/2011/08/09/2132689.html

原文地址:https://www.cnblogs.com/broadview/p/2133924.html