可扩展的所有者界面

时间:2018-08-11 05:15:30

标签: c# oop design-patterns

我正在用C#设计一个简单的城市模拟,其中城市是一个类。这个城市有许多系统,例如RoadSystem和TrafficSystem,它们也是类。 City类汇总了上述类的实例。

class City: ICity
{
    RoadSystem.IRoadSystem       m_roadSystem;
    TrafficSystem.ITrafficSystem m_trafficSystem;
}

示例“系统”代码:

class SimpleRoadSystem : RoadSystem.IRoadSystem
{
    public SimpleRoadSystem(ICity owner)
    {
    }           
}

系统以及城市本身都有接口,允许照常进行替代实施。

我遇到的经典问题是在实例化系统时。由于系统归城市阶层所有,因此我可以将ICity实例传递给它们。系统类可以使用ICity接口从拥有的城市类中提取任何所需的数据。但是,这将SimpleRoadSystem绑定为仅与城市一起使用。但实际上,道路系统是一个通用概念,可用于为可能具有不同接口的区域或城镇实施道路。基本上,将道路系统的所有者仅绑定到城市是一种限制。

所以另一个想法是在城市和道路系统之间具有IRoadSystemOwner接口,该接口由城市实施。

class City: ICity, IRoadSystemOwner, ITrafficSystemOwner,......
{
    RoadSystem.IRoadSystem       m_roadSystem;
    TrafficSystem.ITrafficSystem m_trafficSystem;
}

class SimpleRoadSystem : RoadSystem.IRoadSystem
{
    public SimpleRoadSystem(IRoadSystemOwner owner)
    {
    }           
}

但这无法扩展。该城市可以有任意数量的系统。它实际上是在运行时加载的列表。因此,如果城市需要使用10个不同的系统,则需要预先进行预测并实现10个不同的所有者接口!

基本上,我试图弄清楚如何让RoadSystem拥有的类拥有一个拥有一个肯定拥有者接口的所有者! 但是不能通过不可扩展的继承来实现这个想法。这应该允许拥有的类从其所有者中提取所需的信息。它应该可以很好地扩展,因为一个城市可以在运行时根据数据确定任何数量的系统。

我认为动态转换或通用属性系统似乎有效。 RoadSystem类可以尝试将所有者实例转换为ICity或ITown或IRegion,然后查看哪个成功。 或所有者具有getProperty(key)函数,该函数返回通用对象引用,该引用可以转换为具体类以获取实际数据,例如:

object obj = owner.getProperty("Map")
IMap map = obj as IMap;
if (map == null)
{                
    throw new System.ArgumentException("The map could not be retrieved from owner", "original");
}

除了使用动态强制转换之外,还有其他方法吗?

3 个答案:

答案 0 :(得分:1)

如我所见,“城市类汇总了上述类的实例”是这里问题的根源。然后,您想要一个区域类来汇总相同的类,然后以两个城市应该具有相同子系统的方式重新考虑系统。稍后将导致许多复杂性问题。

当城市对子系统一无所知,因此它们是独立的,并且有一个类World / Execution上下文时,请尝试以不同的方式重新思考(这是所有这些的容器,并且每个人都了解所有信息)

我看不到您希望如何使用它的任何线索,因此我没有提供任何“真实”方法。

using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    public class World
    {
        public List<ICity> Cities { get; set; }
        public List<IRegion> Regions { get; set; }

        public List<IRoadSystem> RoadSystems { get; set; }
        public List<ITrafficSystem> TrafficSystems { get; set; }
        //any other systems you like

        public void AddRoadSystemToCity(IRoadSystem system, ICity city)
        {
        }

        public IRoadSystem GetRoadSystem(ICity city) //or any other rule we would like to use later
        {
            throw new NotImplementedException();
        }
    }

    public interface IRegion
    {
    }

    public interface ITrafficSystem
    {
    }

    public interface IRoadSystem
    {
    }

    public interface ICity
    {
    }
}

答案 1 :(得分:1)

  

但是,这使SimpleRoadSystem只能与城市一起使用。但   实际上,道路系统是一个通用概念,可以用来   在可能有差异的地区或城镇中实施道路   接口。

从您的解释看来,您似乎正在寻找一种神奇的解决方案,该解决方案可以使具体的类与任何协作类型一起使用,而无需为它们创建通用的抽象。

  1. 如果SimpleRoadSystem需要与其他不同的“所有者”实现进行协作,那么除了使用接口来限制关系之外,我没有其他方法。

  2. 如果要为各种不同的“所有者”接口实现IRoadSystem,而每个实现仅与此类“所有者”接口的特定子集相关,那么public class SimpleCityRoadSystem implements IRoadSystem<ICity>会如何。

  3. 您当前的设计采用双向关系,通常应避免这种关系。您尚未解释为什么SimpleRoadSystem需要了解其所有者的原因,但是您是否无法重新设计系统,以使“所有者”告诉IRoadSystem该做什么,并提供必要的数据而不需要{ {1}}知道它是“所有者”吗?

  4. 如果系统组件之间的通信和关系非常复杂并且需要非常灵活,那么消息传递设计可能是最适合的,其中所有组件都使用消息总线发送和侦听消息。

    例如,SimpleRoadSystem可以发送RandomTrafficSystem消息,该消息可以由任何感兴趣的一方处理。

我们根本不了解您的问题域对我们没有帮助。与其解释当前模型及其缺陷,不如将其重点放在解释要解决的问题的细节上。也许完全不同的模型会更合适(例如,将游戏模型与世界,物品(路段,汽车等),坐标等进行匹配。

答案 2 :(得分:0)

也许您需要的是进一步发展自己的领域,并拥有一些可以更好地共享的通用概念。例如,尝试使用一个IRoadSystemOwner来代替RoadSystem,它实际上并不像一个领域概念,而是想出一个类似IAdministrativeDivision的东西。或其他可以更好地体现设计意图的东西。

这是接口隔离原则在域驱动设计中的一种应用,关键是 city region 成为< em>行政区划,以便与道路系统配合使用,并让您自己讨论这些概念。

相关问题