抽象和封装之间有什么区别?

时间:2011-02-11 07:44:51

标签: java oop

  

可能重复:
  difference between abstraction and encapsulation?

Java中封装和抽象之间究竟有什么区别?任何简短的例子也将受到赞赏。

4 个答案:

答案 0 :(得分:8)

抽取和包装是两种口味很好的口味。

封装正在最大限度地减少您向代码用户公开的内容。 “用户”可能是您代码的其余部分,也可能是使用您发布的代码的任何人。

封装有一些明确的好处:

  • 您的代码的用户不依赖于您可能更改的程序部分。当您更改程序时,他们不必更改代码
  • 您可以更好地控制代码和状态在程序生命周期中的确切变化。您必须处理更少的方案,并且需要修复的意外问题更少

我不懂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。列表,数组,字典和任何其他类型的集合类都实现IEnumerableforeach循环结构和整个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);

您可以像使用IAnimalIsHealthy一样使用它们。 IAnimal是一个缩写词,只有get个访问者,set上没有IsHealthy个访问者是封装。

答案 1 :(得分:6)

这两个概念完全不同。

抽象是使基类“抽象”然后扩展其功能的做法。抽象类是具体事物中不存在的东西;它的唯一目的是扩展。想想你是否在编写代表不同物种的课程。你所有不同的物种都可以扩展一个抽象的动物类,因为它们都会像动物一样拥有共同的属性。但是,你永远不会实例化一个动物对象,因为你在世界上看到的每一只动物都是松鼠,狗,或鱼......或某种基础的抽象动物类的具体实现。

封装是将类变量设为私有,然后允许从get和set方法访问它们的做法。这样做的目的是分开访问数据的方式和实现方式。例如,如果您有一个有需求的变量,那么每次更改它时,它也会将第二个变量增加1,然后您将封装该功能;这样你的代码就更可靠了,因为你每次访问原始变量时都不必记住遵守该规则。

如果您需要特定的代码示例,我建议您只进行Google搜索,因为有很多可用的示例。这是两个:

http://www.tutorialspoint.com/java/java_abstraction.htm http://www.tutorialspoint.com/java/java_encapsulation.htm

答案 2 :(得分:4)

封装是为了保护您的成员变量或方法免受外界影响。

抽象是具体实施的方式。这是用户不知道要使用的实现。

答案 3 :(得分:3)

封装是抽象的一部分。抽象概念是创建表示另一个对象的对象之一。通常,原始对象比抽象更复杂。因此抽象是一种表示,通常作为记忆的辅助,用于术语/交流等。可以这样想:抽象艺术是其他东西的表现。方向盘,换档和2/3踏板是汽车工作方式的抽象。

基本上,抽象允许你用很多细节来表示复杂的东西,因为它更简单。在我看来,这与认知科学中的“分块”有关。我们无法将复杂的东西放在脑海中,所以我们通过抽象,然后使用抽象来简化。设计模式是另一个很好的例子。我们可以谈论命令,状态或战略模式等,而不是谈论细节。

封装是形成/创建抽象的一部分。对象的界面越小,抽象就越容易。您无需了解发动机和变速箱如何驾驶汽车,您只需要了解它们的抽象(换档和加速器)。发动机和变速箱的细节被封装(进入界面)以创建抽象。

抽象需要封装,因为抽象不能处理所有真实细节和复杂性(否则它不是抽象)。因此换档是变速箱的不完整表示(或模型),但其完整性足以供日常使用。封装可以被认为是“隐藏细节”,这对于创建更简单的表示是必要的。

讨论“界面”的概念也很重要。在大多数情况下,术语“接口”和“抽象”在这种情况下更不可互换。界面是用户交易或交互的系统的一部分。汽车的接口是方向盘,换档和踏板等。抽象产生一个界面。您不直接处理发动机/变速箱,而是处理各自的接口。

封装的另一个原因是因为我们处理的是不完整的模型/抽象,我们不了解原始的完整复杂性,并且无法信任处理所有变量(因为我们没有了解完整的模型)。这对于解耦很重要,因为没有抽象,交互组件就会彼此了解太多。想一想,因为每辆车都有方向盘,踏板和换档,你可以驾驶任何汽车,无论发动机类型如何等等。此外,变速箱从发动机中抽出。否则每个自定义引擎都需要一个自定义变速箱。

类似地,类是抽象。该类通过其接口表示一些复杂的模型 - 该类的公共成员。该接口是通过封装创建的。该类为其协作者提供了更复杂实现的简化界面。您也可以将其视为“需要了解”的情况。该课程的合作者不需要确切知道它是如何工作的。就像你不需要知道发动机如何驾驶汽车一样。

封装,接口和抽象在内聚和耦合以及代码维护方面发挥着关键作用。如果你没有创建好的抽象,并违反了“需要知道”的原则,那么你的代码就会变得纠结,脆弱,变成一场噩梦,因为没有“缓冲”。 “告诉不要问”的OO概念也与此有关。