假设我有一个门的定义:
class Door
{
public void Lock()
{
// lock the door
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎对我有意义,至少在一段时间内.但现在,我不太确定.如果我有一个想要锁门的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);
}
Run Code Online (Sandbox Code Playgroud)
相反,我们能做的是:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
显然这两个类是强耦合的,两者都可能在实际代码中提取接口,但这不是我所得到的.我的问题是,这是一种更好的方法来模拟两个对象之间的关系吗?还有比这更好的方法吗?我想的越多,aDoor.Lock()的感觉就越少; 它似乎违反了面向对象的设计.
虽然该人"锁定"门,但实际上该人正在切换(或擦拭)门的元件(锁定手柄)并且该操纵导致锁锁定门.你可以想到这一点,虽然这个人正在移动锁舌,但是锁舌是锁门的 - 而不是人.因此,一个更好的表示可能是门有一个锁,并且该人调用lock.lock(),然后设置锁被关闭(锁定).
这里的基本前提是,虽然人正在操纵锁,但这是外部的(函数调用).锁的内部更改(函数内部的代码)实际上是导致门锁定的原因.这个人每次都没有脱下手柄并操纵内部来锁门 - 他们只是在外面切换状态并期望机器内部处理它.
OOP并不是关于在"现实世界"中如何工作的建模.它更多的是管理复杂性.考虑到这一点,门完全锁定是完全可以接受的.即使在现实世界中,除了转动旋钮或钥匙之外,锁门的人不需要知道锁的工作原理.
隐藏抽象背后的复杂想法的细节是OOP如此有用的原因.您使用的抽象与问题域不同.在你给出的例子中,除了如何操作之外,人们不需要知道关于门的任何信息:
class Door
{
public bool Open(){}
public bool Close(){}
public void Lock(){}
public void Unlock(){}
}
Run Code Online (Sandbox Code Playgroud)