今天我从朋友那里听到,封装不仅实现了信息隐藏,还实现了抽象。它是如何实现的?
public class employee {
private String name;
private int id;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
上面的例子实现了封装,我允许类访问我的公共方法而不是私有成员,但这里的抽象在哪里?任何人都可以用一种清晰的方式向我解释抽象。
答案 0 :(得分:9)
有两个不同的东西,信息隐藏和抽象。
信息隐藏使抽象成为可能,但它有所不同。例如,使用您的代码
public class employee {
private String name;
private int id;
public void setName(String name) {
this.name = name;
}
public String getName(){
return name;
}
}
id
字段实际上是隐藏的。这允许人们以与程序的其余部分分离的方式处理id。您的名称字段实际上也是隐藏的,因为您不直接访问名称字段,但getName
和setName
中的代码确实存在。
一旦从其余代码隐藏数据结构,强制通过方法访问,就可以创建一些项目的可替换实现。例如,employee
是概念类person
,因此您可以像这样重写上述内容:
public interface Person {
public abstract String getName();
}
public class Employee implements Person {
private String name;
private int id;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
现在,您的代码可以将Employee
作为Person
来处理。在重写了未明确处理Employee
s的其余代码以处理Person
之后,您可以实现其他类型的Person
并利用非Employee特定任务现在是Person
个任务。
public Customer implements Person {
private String name;
private integer moneySpent;
public String getName() {
return name;
}
}
一个人搜索例程,只要它只对Person
个对象进行索引,现在可以包括对Employee
和Customer
的搜索。这是因为处理Person
对象的代码实际上处理的是Employee
和Customer
个对象共享的更高级别的抽象。
在抽象级别处理对象时,方法的名称在抽象中共享;但是,执行的实际代码取决于对象的未提及的基础类型。换句话说,如果您询问某人(恰好是员工)getName()
,那么它将使用Employee.getName()
函数回复,而Customer
将回复Customer.getName()
功能。由于调用getName()
的代码在Person
上运行,因此它不知道它将处理哪种类型的人,但行为的明显变化(选择正确的代码块)对象基础)仍然发生。这种现象被称为Polymorphisim,如果你是第一次触及这些概念,你会听到Polymorphisim作为一个经常使用的词。
多态行为的一个例子:
public interface Animal {
public abstract String makeSound();
}
public class Cow implements Animal {
public String makeSound() {
return "Moo Moo!";
}
}
public class Dog implements Animal {
public String makeSound() {
return "Ruff Ruff!";
}
}
public class Sheep implements Animal {
public String makeSound() {
return "Baa Baa!";
}
}
// this class demonstrates the polymorphic behavior
public class Farm {
public static void main(String[] args) {
ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Cow());
animals.add(new Sheep());
animals.add(new Dog());
for (Animal animal : animals) {
// this is where the polymorphisim occurs
// each animal will make a different sound
// because the makeSound method is getting
// bound to different blocks of code based
// on the exact type of animal class hiding
// under the Animal abstraction.
System.out.println(animal.makeSound());
}
}
}
预期产出:
Moo Moo!
Baa Baa!
Ruff Ruff!
即使我们从未明确地更改类,我们也从未明确地更改过方法。它是抽象方法与正在改变的显式子类的绑定,这种情况只发生在支持多态性的系统中。
答案 1 :(得分:4)
@ John你的朋友是正确的,通过实现封装,你也实现了抽象。
public class employee {
private String name;
private int id;
public void setName(String name){
name= name+"something that you want to edit";
this.name = name; }
public String getName(){
return name; }
}
以这种方式你已经编辑了你的set方法并隐藏了用户的细节,这只是抽象...... 因此,通过写入getter和setter,你可以隐藏用户来执行不必要的任务......
public void setName(String name){
/*some internal logic suppose in database you want name
*should be added with its id but what user to do with it.*/
this.name = name; }
public String getName(){
/* now suppose you have recieved the name from
*data base it has id but you want user to know only
name then you will write the logic here to show the name.*/
return name; }
我知道将id添加到name是一个愚蠢的例子,但这就是我现在能想到的......但是考虑一个非常大的项目,你多次在set中编写代码(或者调用其他方法来修改它的参数)那么...... 假设你得到了这个名字,但你想在db中以加密形式保存它,那么是什么。 用户不关心加密但是你必须......因为它对用户不利但对你很重要。所以这应该在你的代码中,但对用户隐藏,这就是抽象的全部*(“隐藏来自用户的不合理的详细信息”)*
编辑: - 去源头! Grady Booch说(面向对象分析与设计,第49页,第二版):
“抽象和封装是互补的概念:抽象关注于对象的可观察行为......封装集中于产生这种行为的实现......封装通常是通过信息隐藏实现的,这是一个过程隐藏对象的所有秘密,这些秘密对其基本特征没有贡献。“
从上面你可以得出相同的结论
答案 2 :(得分:1)
我认为他将多态性与封装混淆。多态性可以帮助您实现abstration。
答案 3 :(得分:1)
就我个人而言,我不会说封装是真的关于抽象(虽然我知道如何采取这种方式),它只是允许用户看到或做必要的事情 - 他们只看到类的接口,而不是它的内部工作。在你的情况下它是实现的,因为你只是设置或获取特定类的名称,你永远不会直接访问名称变量,永远不会看到它是如何存储的。因此,您可以将名称变量的名称或类型更改为完全不同的类型,并且类的接口仍然可以工作并且看起来相同。我想这可以从某种意义上说是一种抽象。
定义是松散的,但我认为多态性更多地落入抽象领域,在那里你将实现(比如ArrayList
)与它继承的接口分离(比如,List
。)这样你只需要处理列表界面,底层列表可以是任何东西,但这是一个实现细节,因为你是一个“高于”它的抽象级别,你不需要担心它。当然这是一种简化,有时您需要了解性能原因的实现细节,或者某些操作可能未在您的特定实现中实现或允许。但是从一个松散的观点(和一个纯粹的OO观点)来看,它仍然存在。
无论你理解什么,最重要的是你理解它背后的逻辑,为什么它是一个好主意以及为什么总是以这种方式做事更好(在这种情况下,将字段作为私有和使用getter /设置者访问它们。)
答案 4 :(得分:1)
这里主要是封装,但也有一些抽象。通过使用名为setName()
的方法,使用您的类的代码不需要知道如何实现“设置名称”的操作。就他们所知,你正在呼唤一个web服务并将其设置在某个数据库中。或者你可能完全忽略了参数并且每次都将名称设置为“Steven”。这些事实是从呼叫者那里抽象出来的。
答案 5 :(得分:1)
我认为你不能用这个特定的例子来证明封装。它更像是这样:
interface NameService {
String getName();
}
现在,告诉我:实现此接口的类是否从平面文件,数据库,nosql存储或其他地方获取名称?
答案 6 :(得分:1)
抽象是关于无法实现/实例化的概念/模型。 抽象就是将对象的方法/成员行为限制到其他类。
答案 7 :(得分:1)
但这里的抽象在哪里?
你自己说过:“允许班级访问我的公共方法而不是私人成员” 换句话说:允许其他类访问他们可能访问的内容,并保护他们可能不会访问的内容。
这里的抽象来自公共方法,例如在getName()
中你不需要总是给私有成员值,它可以附加其他值,甚至可以给出完全不同的东西。这就像是说:“告诉我你的名字,不管你怎么把它给我”。也许更好的例子是名为getYourWorkDone()
的方法。原则保持不变:“完成你的工作!怎么样?我不在乎怎么做!”
封装部分来自私有成员。这个类封装了那些私有成员,因此它们被分组以形成类的状态。
答案 8 :(得分:1)
java official documentation for you to understand when to use interface or abstraction.
另外,我不禁注意到您在封装和抽象之间感到困惑,所以这里是 geekforgeeks 网站上它们之间的简单区别
<块引用>封装是数据隐藏(信息隐藏)而,
<块引用>抽象是详细隐藏
(实现隐藏)。
封装将数据和作用于数据的方法组合在一起,数据抽象处理将接口暴露给用户并隐藏实现细节。
答案 9 :(得分:0)
似乎封装和抽象让每个人都感到困惑。如果你问我,那些是极其分散的主题,这绝对没有混淆的范围。
使用“abstract”关键字时会发生抽象,并且在创建类时会发生封装。封装的良好实现涉及将所有数据成员设为私有。
我写了一些可能对你有用的博客文章:
Learn how to use an Abstract Class in Object Oriented Design
答案 10 :(得分:0)
要隐藏数据时要进行抽象;要隐藏数据和代码时要进行封装,即要包装要实现的数据和代码。
您可以使用抽象类或接口来实现抽象。 在抽象类中,我们可以编写具体方法或抽象方法,但在接口中,我们只能使用抽象方法。
您可以使用访问修饰符(例如public,protected,private)来实现封装。 这些访问修饰符控制数据的访问,即数据是公开的(任何人都可以看到)还是受保护的(只能由扩展类访问)还是私有的(对所有人隐藏)。