C# 面向对象设计问题:容器中的责任还是容器?

C# 面向对象设计问题:容器中的责任还是容器?,c#,c++,oop,class-design,C#,C++,Oop,Class Design,我非常注重使我的软件设计灵活可靠,实现这一点的关键概念之一是封装。 最近我遇到了一个特殊的设计问题,我无法(和自己)争论什么是最好的解决方案 一个具体的例子说明了这个问题:一个设备有一个地址(在总线上)。该设备有多个寄存器。寄存器也有一个地址(在设备内部-aka.virtual address/mapped address),因此,例如要写入设备上的寄存器,必须将(registerAddress,value)写入设备的地址。 我无法决定将读/写寄存器的功能放在何处: 1) 寄存器应该能够读写自身

我非常注重使我的软件设计灵活可靠,实现这一点的关键概念之一是封装。 最近我遇到了一个特殊的设计问题,我无法(和自己)争论什么是最好的解决方案

一个具体的例子说明了这个问题:一个设备有一个地址(在总线上)。该设备有多个寄存器。寄存器也有一个地址(在设备内部-aka.virtual address/mapped address),因此,例如要写入设备上的寄存器,必须将(registerAddress,value)写入设备的地址。 我无法决定将读/写寄存器的功能放在何处:

1) 寄存器应该能够读写自身,这意味着它需要了解设备和自身之间的通信通道。这似乎有些奇怪/错误,但我无法解释原因

2) 该设备对寄存器进行读/写操作。寄存器只是设备可以查询/更改的信息(数据、访问权限等)的占位符。这似乎也是错误的,因为读/写寄存器的责任实际上应该在寄存器中(就像文件知道如何读/写自己一样)

什么解决方案最有意义?为什么?也许有一个完全不同的解决方案更有意义

解决方案1

class Device
{
    private CommChan chan;
    private Register register1;
    private Register register2;
    ...

    public Device(int deviceAddress)
    {
        chan = new CommChan(deviceAddress);
        register1 = new Register(0x01, chan);
        ...
    }

    public void DoSomething()
    {
        register1.Write(0x22);
        byte b = register1.Read();
    }
}

class Register
{
    private int address;

    ...

    public Read()
    {
        chan.InitTransfer(address)
        ... // Other setup
        return chan.Read(address);
    }

    public Write()
    {
        chan.InitTransfer(address)
        ... // Other setup
        chan.Write(value);
    }
}
解决方案2

class Device
{
    private CommChan chan;

    public Device(int address)
    {
        chan = new CommChan(address);
    }

    public void DoSomething()
    {
        WriteRegister(0x01, 0x22);
        byte b = ReadRegister(0x01);
    }

    private byte ReadRegister(int address)
    {
        chan.InitTransfer(address)
        ... // Other setup
        return chan.Read(address);
    }

    private void WriteRegister(int address, int value)
    {
        chan.InitTransfer(address)
        ... // Other setup
        chan.Write(value);
    }
}

问题实际上是关于“注册是否应该是一个单独的实体?”。好吧,这取决于你。您需要回答这样一个问题:为什么寄存器必须是类?

从逻辑上讲,总线本身就是一个对象。读取或写入寄存器是一种总线操作,不同的总线有不同的方式访问寄存器。使用ReadRegister和WriteRegister方法创建总线接口


这当然是一个考虑因素,我认为在另一种类型的总线上运行此代码的可能性很小。

寄存器应该是一个类的原因是它在一个中心位置收集有关寄存器的信息。寄存器还可能具有读/写/只读、访问时间等属性。如果register是一个类,那么很容易理解为什么这是一个好主意(仅涉及这一点)。然而,如果一个人考虑到这一点,那么他就需要了解沟通渠道,我认为它开始变得丑陋起来。我在寻找一个很好的解释,为什么一个解决方案比另一个更好,或者只是对它们的一些想法。如果CommChan绝对需要启动转移,那么没有办法登记它自己的吗?为什么这个C++?很明显,这是C代码,而C++解决方案可能看起来与C语言解决方案不同。