C# OOD与主客体混淆

C# OOD与主客体混淆,c#,oop,C#,Oop,假设我对门有一个定义: class Door { public void Lock() { // lock the door } } 这对我来说似乎有道理,至少在一段时间内是这样。但现在,我不太确定。如果我有一个Person对象想要锁一扇门,他会调用aDoor.lock()。但在现实生活中,我们并不是通过告诉门自己锁门来锁门的 似乎一个更准确的情况模型是,如果一个人有足够的权力锁门,他可以直接修改阿多尔的状态。例如,aCat不应能够将aDoor.IsLo

假设我对门有一个定义:

class Door
{
    public void Lock()
    {
        // lock the door
    }
}
这对我来说似乎有道理,至少在一段时间内是这样。但现在,我不太确定。如果我有一个Person对象想要锁一扇门,他会调用aDoor.lock()。但在现实生活中,我们并不是通过告诉门自己锁门来锁门的

似乎一个更准确的情况模型是,如果一个人有足够的权力锁门,他可以直接修改阿多尔的状态。例如,aCat不应能够将aDoor.IsLocked设置为true。如果属性支持参数,我可以看到如何使用属性执行此操作:

class Person
{
    public void LockDoor(Door door)
    {
        door.IsLocked(this) = true;
    }
}

class Door
{
    bool isLocked;

    public bool IsLocked(Person person)
    {
        set
        {
            if(person != null) // ensure there is a real person trying to lock the door
            {
                this.isLocked = value;
            }
        }
    }
}

static void Main()
{
    Person personFromThinAir = new Person();
    Door doorFromThinAir = new Door();
    personFromThinAir.LockDoor(doorFromThinAir);
}
相反,我们能做的是:

class Person
{
    public void LockDoor(Door door)
    {
        door.SetLocked(this, true);
    }
}

class Door
{
    bool isLocked;

    public void SetLocked(Person person, bool locked)
    {
        if(person != null)
        {
            this.isLocked = locked;
        }
    }
}

显然,这两个类是强耦合的,它们都可能在实际代码中提取接口,但这不是我要说的。我的问题是,这是模拟两个对象之间关系的更好方法吗?还有比这更好的方法吗?我想得越多,对aDoor.Lock()的理解就越少;它似乎违反了面向对象的设计。

面向对象并不是真正意义上的在“真实世界”中建模。更重要的是管理复杂性。考虑到这一点,这是完全可以接受的门锁自己。即使在现实世界中,锁门的人也不需要知道锁的工作原理,只需要转动把手或钥匙

将复杂想法的细节隐藏在抽象背后是OOP如此有用的原因。您使用的抽象不同于问题域。在您给出的示例中,除了如何操作门外,此人不需要了解任何关于门的知识:

class Door
{
    public bool Open(){}
    public bool Close(){}
    public void Lock(){}
    public void Unlock(){}
}
尽管该人员“锁定”车门,但实际上该人员正在门的一个元件(锁把手)上进行切换(或抖动),并且该操作会导致锁锁定车门。你可以这样想,虽然人在移动门闩,但门闩是锁上门的东西,而不是人。因此,更好的表示可能是门有一把锁,这个人调用lock.lock(),然后将锁设置为关闭(锁定)


这里的基本前提是,尽管用户正在操作锁,但这是外部的(函数调用)。锁的内部变化(功能内部的代码)实际上是导致门锁的原因。人们并不是每次都取下把手,操纵里面来锁上门——他们只是简单地在外面切换一个状态,并期望里面的机械来处理它。

我最感兴趣的设计问题是如何处理储物柜和储物柜之间的耦合,因为有这样的要求必须满足以下条件才能允许锁定/解锁。我看看这个问题,想象一个游戏,玩家有时可能是人类,但有时是猫(根据给出的示例),并且可能
是人类
是锁定/解锁的唯一要求。但你也可能希望有门,需要匹配的钥匙在玩家的收藏中,以便锁定/解锁。如果是这样,您必须将其添加到标准中。也许有些门只能从一侧锁定,而不能从另一侧锁定,因此必须将玩家的位置添加到标准中。你可以进一步增加一些玩家可能拥有的开锁技能(毫无疑问,是猫贼),让他们即使没有钥匙也有机会开锁(但不锁)。等等等等

可以想象对象之间的对话,如:

Player: "I am trying to unlock you."
Lock: "Do you meet requirement A?"
Player: "Yes"
Lock: "Do you meet requirement B?"  // Only some doors would ask this.
Player: "Yes"
Lock: "OK, you succeed.  I am unlocked!"
但是,您可能不想公开涉及的字段,也不想让不需要了解锁定/解锁要求的对象看到的播放器界面变得混乱

我不是一名C#程序员,我做Java已经有一段时间了,但我认为Java中的一种方法可能也适用于C#,即让玩家对象将
lock\u unlock\u凭证
内部类的实例作为参数传递给Door对象的
get\u locked
/
get\u unlocked
方法(或按照建议锁定对象。)
lock\u unlock\u credentials
对象将具有回调方法,由于它是Player的一个内部类,因此可以访问Player对象的相关字段,但这些字段不会在Player之外公开。然后,可锁定对象可以使用这些回调方法检查是否满足要求您无法避免由需求导致的耦合,但这种方式将细节保留在播放器和可锁定对象之间交互的内部


不确定同样的内部类方法是否适用于C#,但将其作为思考的对象。

说得好-输入速度比我快!这也有助于实际教授这个概念大约4或5年;)让我告诉你,你最终会找到大量的示例来尝试通过OOP的概念