我似乎不太了解两个OOP概念.你能解释什么是抽象和多态,最好用真实的例子和代码吗?
谢谢.
想象一下分数类:
class fraction: int denominator int numerator
现在有两个对象:
fraction(obj1): denominator=-1 numerator=-1 fraction(obj2): denominator=1 numerator=1
两个对象的值均为1 : (1/1) == (-1)/(-1)
. 你不会指望他们与外界有任何不同.这是抽象.您将对象保存的数据抽象为逻辑视图,即使在幕后,也有其他事情.从理论上讲,你有一个等价关系,具有不同的等价组:
[1]=(1, 1), (-1, -1), (5, 5), ... [2]=(2, 4), (-2, -4), ... ...
并且有一个抽象函数将内部细节抽象到外部:
f((1, 1)) = [1] f((-1, -1)) = [1]
它从具体值映射到对象的抽象值.你可以通过编写一个构造函数映射(-1,-1)到(1,1)并为你的类编写一个equals函数来做到这一点.
想象一下笔和两个派生类:
class pen: void draw(int x, int y) class pen_thin extends pen: void draw(int x, int y) { color(x, y) = green; } class pen_thick extends pen: void draw(int x, int y) { color(x, y) = green; color(x, y+1) = green; } and two objects: pen_thin(p1) pen_thick(p2)
两支笔都可以画画.你的一般"笔"不能自拔.它只是pen_thin,pen_thick和许多其他笔的界面.你说:obj1.draw(1,0); obj1是粗还是薄笔对于你作为用户来说无关紧要,在编译时也不对编译器无关紧要.该调用表现为多态.它是动态多态(在运行时发生),而这正是人们通常的意思.静态多态性在编译时发生:
class colorizer: void colorize(shirt s) void colorize(pants p)
这叫做重载.你打电话obj.colorize(something)
.如果你用衬衫参考来称呼它,它会打电话给衬衫的版本.如果你用裤子参考调用它,它将调用裤子版本.这里做的选择是在编译时.
这两者是面向对象范式最重要的特征之一.
面向对象将软件建模为真实世界对象.但是,对客户可能具有的所有属性或员工拥有的所有属性进行建模将太难(并且无用).
通过仅列出对象的有趣属性,OO可以有效地使用该对象用于特定域.这是抽象.
例如,HR系统中的员工可能具有与Online BookStore非常不同的属性.我们抽象细节使得有用.
根据"类型",对象的行为可能会有所不同,同时保持相同的界面.
这意味着什么?
例如,在线商店系统可能有两个子类Employee
A)内部员工.
B)承包商
以及计算内部购买折扣的方法
内部员工的折扣计算如下:公司每个工作年度的10%+ 2%+每个工作年度的2%... mmhh孩子
承包商的折扣是10%
以下代码计算支付金额:
public Amount getAmountToPay( Product product, Employee internalCustomer ) { Amount amount = product.getPrice(); amount.applyDiscount( internalCustomer.getDiscount() ); return amount; }
会对两种不同类型的员工产生不同的结果
class Employee { public int getDiscount(); } class InternalEmployee extends Employee { public int getDiscount() { return 10 + 2 * getWorkedYears() + 2 * getNumberOfChilds(); } } class Contractor extends Employee { public int getDiscount() { return 10; } }
这是行动中的多态性.而不是像
Amount amount = product.getPrice(); if( employee.isContractor() ) { amount.applyDiscount( 10 ); } else if( employee.isSomthingElse() ) { amount.applyDiscount( 10 * 2 * getYrs() + 2 * getChilds() ); } else if ( employee.contidions, condigions, conditions ) { amount.applyDiscount( getSomeStrageRuleHere() ); }
我们让运行时选择要计算的那个.就像程序的行为不同,具体取决于类型:
Amount amount = product.getPrice(); amount.applyDiscount( internalCustomer.getDiscount() ); return amount;
顺便说一下,在这个例子中,"Amount"是现实生活概念的抽象,也可以表示为double或Integer,但也许我们内部的interestion方法如果设置在它自己的类中会更好.
我希望这有帮助.
抽象和多态性是关键概念,绝不仅限于OO.更令人困惑的是,"抽象"这个词被多种方式使用.这是一个快速备忘单,有一个例子:
数据抽象意味着信息隐藏.通常隐藏的是数据结构的表示.示例:我实现了集合,但是我没有告诉您集合是表示为列表,平衡二叉树还是非平衡二叉树.做得对,我可以在不破坏您的代码的情况下更改表示.
多态性意味着重用不同的类型.因此,通过我的设置示例,您可以使用相同的代码创建社会安全号码集,全名集或者成果集.
显然,您可以定义一个既抽象又具有多态性的类.
多态性进一步混淆,因为有两种方法可以实现多态性.在参数多态中,您可以使用任何类型的值重用该集合,或者可以使用满足某些约束的任何类型.的最明显的例子是C++模板 ; 如果你写
class Set{ ... }
然后T
是集合中包含的对象类型(符号
表示所谓的"类型参数",这是使其成为参数多态的原因).
在子类型多态性中,只能将类型重用于类型为特定类型的子类型的对象.例如,您可能只能创建提供小于或等于方法的对象的集合.在一个真正的面向对象的语言,如Smalltalk或Ruby,提供所谓的鸭子打字(我们尖头理论家有时称之为行为子类型),这种方法的存在已经足够了.在像Java或C++这样将子类型与继承混合在一起的语言中,您对多态的使用可能仅限于特定类的子类.(Java通过在类上使用一种形式的子类型而在接口上使用另一种形式来进一步混淆问题.)
最后,像我这样的老屁谈论程序抽象,这意味着能够将一堆经常一起使用的语句放到一个程序或方法中,然后再重复使用.这可能与你的问题没有密切关系.
那么,你是否感到困惑?
抽象是指在不包括背景细节或解释的情况下表示基本特征的行为.类使用抽象概念,并被定义为抽象属性列表.
软件抽象的一个例子是Java的Object.equals(Object o)
方法.您知道它会将此对象与作为参数传入的对象进行比较,但您不知道,也不需要知道它将如何实现(除非您是该类的实现者).
多态性意味着能够采用多种形式.方法在不同的实例中可能具有不同的行为.行为取决于操作中使用的数据类型.
多态性的一个经典示例使用以Animal类为根的继承树.所有Animal都有一个makeNoise()
方法,但Dog类和Cat类以不同的方式实现它.这允许您使用Animal参考类型引用任何Dog's和Cat's.
Animal a = new Dog(); Animal b = new Cat();
现在,您可以调用makeNoise()
任一Animal实例,并知道它会产生适当的噪音.如果你有一个动物集合,并且你在运行时不确切知道每个动物的真实类型,那么这个特别有用.