OOP最重要的一个方面是数据隐藏。有人可以用一段简单的代码来解释数据隐藏的确切原因以及我们需要它的原因吗?
答案 0 :(得分:6)
Data or Information Hiding是David Paranas提出的设计主体。
它说你应该隐藏 设计决策的一部分 可能会改变的程序 从该计划的其他部分,那里 通过保护其他部分 受到变化的影响 第一部分。
封装是一种支持数据隐藏的编程语言功能。 但请注意,即使没有封装,您也可以隐藏数据\信息。例如,使用非面向对象编程语言中的模块或函数。 因此封装不是数据隐藏,而只是实现它的手段。
在进行封装时,如果忽略底层主体,那么你将没有一个好的设计。例如,考虑这个类 -
public class ActionHistory
{
private string[] _actionHistory;
public string[] HistoryItems
{
get{return _actionHistory; }
set{ _actionHistory = value; }
}
}
此调用封装了一个数组。但它并没有隐藏使用string []作为内部存储的设计决策。如果我们想稍后更改内部存储,它也会影响使用此类的代码。
更好的设计将是 -
public class ActionHistory
{
private string[] _actionHistory;
public IEnumerable<string> HistoryItems
{
get{return _actionHistory; }
}
}
答案 1 :(得分:5)
我猜测数据隐藏你的意思是像封装或者在一个对象中有变量而只是通过get和modify方法暴露它,通常是你想要的强制执行一些设置值的逻辑?
public class Customer
{
private decimal _accountBalance;
public decimal GetBalance()
{
return _accountBalance;
}
public void AddCharge(decimal charge)
{
_accountBalance += charge;
if (_accountBalance < 0)
{
throw new ArgumentException(
"The charge cannot put the customer in credit");
}
}
}
即。在这个例子中,我允许消费类获得Customer
的平衡,但我不允许他们直接设置它。但是我已经公开了一种方法,允许我通过_accountBalance
方法中的费用添加它来修改类实例中的AddCharge
。
这是您可能觉得有用的article。
答案 2 :(得分:1)
信息隐藏(或更准确地说是封装)是限制直接访问您的类信息的做法。我们在C#中称为属性使用getter / setter或更高级的构造。
这使我们可以管理如何访问数据,因此我们可以在以后需要时对输入进行清理并格式化输出。
这个想法是在任何公共界面上,我们不能相信调用主体做正确的事情,所以如果你确定它只能做正确的事情,你就会有更少的问题。
示例:
public class InformationHiding
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
/// This example ensures you can't have a negative age
/// as this would probably mess up logic somewhere in
/// this class.
private int _age;
public int Age
{
get { return _age; }
set { if (value < 0) { _age = 0; } else { _age = value; } }
}
}
答案 3 :(得分:1)
想象一下,您班级的用户正试图想出让您的班级不再履行合同的方法。例如,您的Banking对象可能有一个合同,确保所有交易都记录在日志中。假设银行的TransactionLog的变异是公开可访问的;现在,消费类可以启动可疑事务并修改日志以删除记录。
这是一个极端的例子,但基本原则保持不变。由班级作者维护班级的合同义务,这意味着你要么需要承担较弱的合同义务(减少班级的有用性),要么你需要非常小心你的州如何变异。
答案 4 :(得分:1)
以下是一个例子:
public class Vehicle
{
private bool isEngineStarted;
private void StartEngine()
{
// Code here.
this.isEngineStarted = true;
}
public void GoToLocation(Location location)
{
if (!this.isEngineStarted)
{
this.StartEngine();
}
// Code here: move to a new location.
}
}
如您所见,isEngineStarted
字段是私有的,即。从班级本身可以访问。事实上,当调用Vehicle
类型的对象时,我们确实需要将车辆移动到某个位置,但不需要知道如何这样做。例如,对于调用者对象,如果引擎启动与否则无关紧要:如果不是,则在移动到某个位置之前,Vehicle
对象启动它。
主要是为了使代码更易于阅读和使用。类可能有几十个或几百个仅由它们使用的字段和属性。将所有这些领域和财产暴露给外界将会令人困惑。
另一个原因是控制私有字段/属性的状态更容易。例如,在上面的示例代码中,假设StartEngine
正在执行某些任务,然后将true
分配给this.isEngineStarted
。如果isEngineStarted
是公开的,则另一个类可以将其设置为true
,而无需执行StartEngine
所做的任务。在这种情况下,isEngineStarted
的值将不可靠。
答案 5 :(得分:0)
通过数据隐藏,您可能是指封装。封装由维基百科定义如下:
封装隐藏了功能性 来自对象的类的详细信息 发送消息。
为了进一步说明,在设计课程时,您可以设计公共和私人成员。该类将其公共成员公开给程序中的其他代码,但只有该类中编写的代码才能访问私有成员。
通过这种方式,类暴露了一个公共接口,但可以隐藏该接口的实现,其中可以包括隐藏类所持有的数据的实现方式。
这是一个简单的数学角度类的示例,它暴露了度和弧度的值,但数据的实际存储格式是隐藏的,并且可以在将来更改而不会破坏程序的其余部分。
public class Angle
{
private double _angleInDegrees;
public double Degrees
{
get
{
return _angleInDegrees;
}
set
{
_angleInDegrees = value;
}
}
public double Radians
{
get
{
return _angleInDegrees * PI / 180;
}
set
{
_angleInDegrees = value * 180 / PI;
}
}
}
答案 6 :(得分:0)
数据隐藏定义为通过命名与基类方法同名的新类方法,在派生类中隐藏基类方法。
class Person
{
public string AnswerGreeting()
{
return "Hi, I'm doing well. And you?";
}
}
class Employee : Person
{
new public string AnswerGreeting()
{
"Hi, and welcome to our resort.";
}
}
在这个c#代码中, new 关键字阻止编译器发出警告,指出 AnswerGreeting 的基类实现被实现的方法隐藏了派生类中的相同名称。也称为&#34;通过继承隐藏数据&#34;。