C#面向对象设计模式纵横谈 学习笔记3 Abstract Factory 抽象工厂

本文探讨了在软件开发过程中,如何利用抽象工厂模式来有效应对不同系列对象构建的需求变化,特别是当对象间存在相互依赖关系时。文章通过游戏开发场景为例,详细讲解了从简单工厂到抽象工厂模式的转变过程,以及如何通过抽象工厂模式降低系统耦合度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这一讲的内容首先说明了对象创建的方法如

Road road = new Road();

这样我们就创建了一个路的实例。

但是现在我们问题出现了,如果我们现在路变了,假设我们的路变成了水泥路,那么我们在使用路的代码里需要将所有的Road road = new Road()编程实例为一个水泥路。

那么我们现在知道了new的问题的所在,实现依赖,不能应对"具体实例化类型"的变化。

那么这里有变化我们需要封装这个变化点。因为变化点在对象创建这个地方,那么我们就将对象创建进行变化。那么最简单的封装就是

class RoadFactory
{
    
public static Road CreateRoad()
    
{
        
return new Road();
    }

}

 

那么我们创建Road的时候就可以使用 Road road = RoadFactory.CreateRoad();

那么如果我们将这个Road类作为抽象基类,CreateRoad函数实现根据需求返回相应的派生类。那么,加入需求有所变化的时候,我们可以不变化其他调用的代码,只需要扩展Road的派生类,并修改CreateRoad的实现。这样可以稍微解决new造成的问题。

那么课程中假设了现在有一个游戏的开发场景。那么我们现在需要建立一系列对象,并且这些对象之间相互依赖

class RoadFactory
{
    
public static Road CreateRoad()
    
{
        
return new Road();
    }


    
public static Building CreateBuilding()
    
{
        
return new Building();
    }


    
public static Tunnel CreateTunnel()
    
{
        
return new Tunnel();
    }


    
public static Jungle CreateJungle()
    
{
        
return new Jungle();
    }

}

那么我们现在通过RoadFactory产生了一组对象。那么我们这一系列对象都是通过RoadFactory来产生。现在问题又出现了,假设我们现在这一系列的对象Road、Building、Tunnel、Jungle都变化了,那么我们是否需要在RoadFactory里来修改每个方法呢?并且,我们也要修改调用创建对象的代码。所以,我们需要将调用创建对象代码和抽象工厂的创建对象的方法相对稳定下来。那么简单工厂的问题如下:

不能应对"不同系列对象"的变化。比如有不同风格的游戏场景--对应不同风格的道路、房屋、地道……

那么我们看下来抽象工厂如何来解决这个问题。

抽象工厂的动机:在软件系统中,经常面临着"一系列相互依赖的对象"的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种"封装机制"来避免客户程序和这种"多系列具体对象创建工作"的紧耦合。

抽象工厂的意图:提供一个接口,让该接口负责创建一系列"相关或者相互依赖的对象",无需指定它们具体的类。

我们先将较稳定的抽象类表现出来

public abstract class Road

}

public abstract class Building

}


public abstract class Tunnel

}


public abstract class Jungle

}


public abstract class FacilitiesFactory
{
    
public abstract Road CreateRoad();
    
public abstract Building CreateBuilding();
    
public abstract Tunnel CreateTunnel();
    
public abstract Jungle CreateJungle();
}

 

这里我们存在一个抽象工厂类,他里面的抽象方法返回的是抽象的基类

 

public class ModenRoad : Road

}


public class ModenBuilding : Building

}


public class ModenTunnel : Tunnel

}


public class ModenJungle : Jungle

}


public class ModenFacilitiesFactory : FacilitiesFactory
{

    
public override Road CreateRoad()
    
{
        
return new ModenRoad();
    }


    
public override Building CreateBuilding()
    
{
        
return new ModenBuilding();
    }


    
public override Tunnel CreateTunnel()
    
{
        
return new ModenTunnel();
    }


    
public override Jungle CreateJungle()
    
{
        
return new ModenJungle();
    }

}

这里是抽象类和抽象工厂类的一个具体实现,这一块是在抽象工厂类里变化是比较快的。

那么我们如何通过抽象类和抽象工厂类来产生对象呢?如下面代码

public class GameManager
{
    FacilitiesFactory faciliesFactory;
    
public GameManager(FacilitiesFactory facilitiesFactory)
    
{
        
this.faciliesFactory = faciliesFactory;
    }


    
public void BuildGameFacilites()
    
{
        Road road 
= faciliesFactory.CreateRoad();

        Building building 
= faciliesFactory.CreateBuilding();

        Tunnel tunnel 
= faciliesFactory.CreateTunnel();

        Jungle jungle 
= faciliesFactory.CreateJungle();
    }

}

 

我们在客户端使用这个GameManager类

static void Main(string[] args)
{
    GameManager manager 
= new GameManager(new ModenFacilitiesFactory());
    manager.BuildGameFacilites();
}

那么我们分析代码在抽象类稳定的情况下,就是说我们这个游戏不会添加新的建筑物的情况下,我们的变化点在扩展抽象类,和Main函数里的ModenFacilitiesFactory。当我们增加一种风格的建筑类型时,我们仅仅只需要新扩展Road、Building、Tunnel和Jungle及FacilitiesFactory,在客户端调用的时,也仅仅需要修改GameManger的构造代码,甚至我们连构造代码都可以不用修改,可以通过WebConfig通过反射来实例花这个FacilitiesFactory类。但是,如果我们要新增加一种建筑,而不是扩展建筑的风格,抽象工厂就不适用了,因为,我们需要修改抽象类、抽象工厂类、GameManager类、GameManager的构造代码,可以说处处需要修改,可以说这个是紧耦合。

总结一下抽象工厂模式的几个要点:

  • 如果没有应对"多系列对象构建"的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的静态工厂完全可以。
  • 系列对象"指的是这些对象之间有相互依赖、或作用的关系,例如游戏开发场景中的"道路"与"房屋"的依赖,"道路"与"地道"的依赖。
  • Abstract Factory模式主要在于应对"新系列"的需求变动。其缺点在于难以应对"新对象"的需求变动。就是说在抽象基类里,我不会增加一个抽象基类。
  • Abstract Factory模式经常和Factory Method模式共同组合来应对"对象创建"的需求变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值