【发布时间】:2011-02-11 07:44:50
【问题描述】:
【问题讨论】:
-
请更正问题标题中的错字。干杯
-
这是作业吗?如果有,请添加作业标签。
【问题讨论】:
抽象和封装是两种很好的味道,在一起味道很好。
封装 正在最大限度地减少您向代码用户公开的内容。该“用户”可能是您的代码的其余部分,或者使用您发布的代码的任何人。
封装有一些明确的好处:
我不懂Java,但是这里有一个用C#封装的小例子:
public class Giraffe
{
public Giraffe(int heightInFeet)
{
this.heightInFeet = heightInFeet;
this.numberOfSpots = heightInFeet * 72;
}
public override string ToString()
{
return "Height: " + heightInFeet + " feet"
+ " Number of Spots: " + numberOfSpots;
}
private int heightInFeet;
private int numberOfSpots;
}
不是暴露numberOfSpots,而是封装在类中,并通过ToString方法暴露。
抽象使用扩展点让选择推迟到运行确切代码的不同部分。该选择可以在您程序的其他地方、另一个程序中或在运行时动态进行。
抽象还有很多好处:
C# 中一个高度使用的抽象是IEnumerable。列表、数组、字典和任何其他类型的集合类都实现了IEnumerable。 foreach 循环结构和整个 LINQ 库都基于该抽象:
public IEnumerable<int> GetSomeCollection()
{
// This could return any type of int collection. Here it returns an array
return new int[] { 5, 12, 7, 14, 2, 3, 7, 99 };
}
IEnumerable<int> someCollectionOfInts = GetSomeCollection();
IEnumerable<string> itemsLessThanFive = from i in someCollectionOfInts
where i < 5
select i.ToString();
foreach(string item in itemsLessThanFive)
{
Console.WriteLine(item);
}
您也可以轻松编写自己的抽象:
public interface IAnimal
{
bool IsHealthy { get; }
void Eat(IAnimal otherAnimal);
}
public class Lion : IAnimal
{
public Lion()
{
this.isHealthy = true;
}
public bool IsHealthy
{
get { return isHealthy; }
}
void Eat(IAnimal otherAnimal)
{
if(otherAnimal.IsHealthy && !(otherAnimal is SlimeMold))
{
isHealthy = true;
}
else
{
isHealthy = false;
}
}
private bool isHealthy;
}
IAnimal someAnimal = PullAnAnimalOutOfAWoodenCrate();
Console.WriteLine("The animal is healthy?: " + someAnimal.IsHealthy);
您可以同时使用两者,就像我对 IAnimal 和 IsHealthy 所做的那样。 IAnimal 是一个抽象,只有 get 访问器,IsHealthy 上没有 set 访问器是封装。
【讨论】:
这两个概念完全不同。
抽象是使基类“抽象”然后扩展其功能的做法。抽象类是在具体事物中不存在的东西。它的唯一目的是扩展。想想你是否正在编写类来代表不同的物种。您所有不同的物种都可能扩展一个抽象的 Animal 类,因为它们都将共享作为动物的共同属性。但是,您永远不会实例化 Animal 对象,因为您在世界上看到的每一种动物都是松鼠、狗或鱼……或者是该基础抽象动物类的某种具体实现。
封装是将类变量设为私有,然后允许从 get 和 set 方法访问它们的做法。这样做的目的是将您的数据访问方式和实现方式分开。例如,如果您有某个变量有一个要求,即每次更改它时,它也会将第二个变量增加 1,那么您将封装该功能;这样您的代码就更可靠了,因为您不必记住每次访问原始变量时都遵守该规则。
如果您想要特定的代码示例,我建议您只进行谷歌搜索,因为有很多类似的示例可用。这里有两个:
http://www.tutorialspoint.com/java/java_abstraction.htm http://www.tutorialspoint.com/java/java_encapsulation.htm
【讨论】:
封装是为了保护你的成员变量或方法不受外界影响。
抽象是有具体实现的方式。那就是用户不知道要使用哪个实现。
【讨论】:
封装是抽象的一部分。抽象的概念是创建一个对象来表示另一个对象。通常,原始对象比抽象对象更复杂。因此,抽象是一种表示,通常作为记忆的辅助,用于术语/交流等。可以这样想:抽象艺术是其他事物的表示。方向盘、换档和 2/3 踏板是汽车工作方式的抽象。
基本上,抽象允许您将具有很多细节的复杂事物表示为更简单的事物。在我看来,这与认知科学中的“分块”有关。我们无法将复杂的事情留在脑海中,所以我们通过抽象来简化,然后使用抽象。设计模式是另一个很好的例子。与其谈论细节,我们可以谈论命令、状态或策略模式等。
封装是形成/创建抽象的一部分。对象的接口越小,就越容易抽象。你不需要知道发动机和变速箱是如何驱动汽车的,你只需要了解它们的抽象概念(换档和加速器)。引擎和变速箱的细节被封装(到接口中)以创建抽象。
抽象需要封装,因为抽象不能处理所有真实的细节和复杂性(否则它不是抽象)。因此,换档是变速箱的不完整表示(或模型),但对于日常使用来说足够完整。封装可以被认为是“隐藏细节”,这是创建更简单的表示所必需的。
讨论“接口”的概念也很重要。在大多数情况下,在这种情况下,术语“接口”和“抽象”更难互换。接口是系统的一部分,用户与之打交道或交互。汽车的接口是方向盘、换档和踏板等。抽象产生一个接口。您不直接处理发动机/变速箱,而是处理它们各自的接口。
封装的另一个原因是因为我们正在处理不完整的模型/抽象,我们不了解原始的全部复杂性,并且不能信任处理所有变量(因为我们不了解完整模型)。这对于解耦很重要,因为如果没有抽象,交互的组件会彼此了解太多。想想看,因为每辆车都有方向盘、踏板和换档装置,你可以驾驶任何汽车,不管发动机类型等。此外,变速箱是从发动机中抽象出来的。否则每个定制引擎都需要定制变速箱。
同样,类是一种抽象。类通过它的接口——类的公共成员来表示一些复杂的模型。该接口是通过封装创建的。该类向其合作者提供了其更复杂实现的简化接口。您也可以将其视为“需要知道”的情况。类的协作者不需要确切地知道它是如何工作的。就像你不需要知道引擎是如何驱动汽车的一样。
封装、接口和抽象在凝聚力和耦合以及代码维护方面发挥着关键作用。如果你没有创建好的抽象,并且违反了“需要知道”的原则,那么你的代码就会变得纠缠不清、脆弱,并且是改变的噩梦,因为没有“缓冲”。 OO 的“告诉不要问”的概念也与此有关。
【讨论】: