设计模式——工厂三兄弟+反射


故事背景:
小菜到一家单位面试, 面试官出的题是:用任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数字和运算符号,得到结果即可。
小菜写了程序,功能实现了,但是忽略了一个很关键的问题,考官的问题是用任意一种面向对象语言实现。小菜将所有代码一股脑写到了主函数中,明显是面向过程的思想。
公司要求采用面向对象的方式实现程序,是因为面向对象程序代码可复用性强,容易扩展,容易维护,代码质量更高。下面看看三工厂模式是如何实现的?

简单工厂模式

初识

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。很多人认为:简单工厂模式不能说是一个设计模式,说它是一种编程习惯可能更恰当些。

优点

工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。使程序更加灵活,复用性高。

计算器例子UML类图
在这里插入图片描述

理解:例如,小菜编译的计算器,根据客户端的选择条件动态实例化相关的类,对于客户来说,去除了与具体产品的依赖。将逻辑判断部分放到工厂类,客户端代码给出具体哪个运算即可。如果要更改界面,实现的逻辑都是一样的,所以工厂代码是可以复用的。

缺点
  • 一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  • 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。

工厂方法模式

初识

工厂方法模式(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
简单工厂里将加减乘除运算都放到一个工厂类中,较简单。而工厂方法中有加减乘除工厂子类继承工厂父类,实现一个工厂子类对应一个运算子类。

优点
  • 工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。

  • 在系统中添加产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

缺点

在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。

计算器例子UML类图
在这里插入图片描述

实例:雷锋工厂
static void Main(string[] args)
{
    
    IFactory factory = new UndergrauateFactory();
     
    LeiFeng student = factory.CreateLeiFeng();

    student.BuyRice();
    student.Sweep();
    student.Wash();

    Console.ReadKey();
}

class LeiFeng
{
    public void Sweep()
    {
        Console.WriteLine("扫地");
    }

    public void Wash()
    {
        Console.WriteLine("洗衣");
    }

    public void BuyRice()
    {
        Console.WriteLine("买米");
    }
}

class Undergraduate:LeiFeng
{

}

class Volunteer:LeiFeng
{

}



interface IFactory//工厂接口
{
    LeiFeng CreateLeiFeng();
}

class UndergrauateFactory:IFactory//大学生工厂类
{
    public LeiFeng CreateLeiFeng()
    {
        return new Undergraduate();//实例化大学生

    }
}

class VolunteerFactory:IFactory//志愿者工厂类
{
    public LeiFeng CreateLeiFeng()
    {
        return new Volunteer();
    }
}

抽象工厂模式

初识

抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

优点
  • 易于交换产品系列,由于具体工厂类,在一个应用中只需在初始化时出现一次,这就使得改变一个应用的具体工厂变得很容易,它只需要改变具体工厂即可使用不同的产品配置。
  • 它让具体的创建实例过程与客户端分离,客户端是通过他们抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
缺点

增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。

实例

实例:一个程序要更换数据库,两种数据库分别为:Sqlserver与Access,其数据库中的表又有User表与Department表(在这进行举例)。
例子UML类图
在这里插入图片描述
理解:声明了IUser接口与IDepartment接口,用于客户端访问,在客户端实例化时解除了与具体数据库访问的耦合。

反射

引入命名空间:

using System.Reflection;

是否记得在简单工厂模式中,我们用到了switch或者if。有用到switch和if的地方,我们都可以考虑利用反射技术来去除,以解除分支带来的耦合。

这其实将会引申一个概念:依赖注入(DI),或者称为控制反转,将传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理,什么意思?就是直观上代码里看不到new 对象,这个操作交给了外部容器,这样将会大大降低程序的耦合性。比如:Spring框架的IoC容器。

常规的实例化:

IUser result=new SqlserverUser();

反射实例化的写法:

IUser result=(IUser)Assembly.Load("抽象工厂模式").CreateInstance("抽象工厂模式.SqlserverUser");

反射和直接new有什么区别呢?答案就在于:反射使用的字符串,也就是说可以用变量来处理。而new的常规方法是已经编译好了的,不能随意灵活更换其实例化对象。所以,如果我们用配置文件的方式,能灵活替换我们想要的实例化对象。

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值