我对面向对象编程(OOP)很陌生。虽然我理解什么是多态(polymorphism),但我无法理解它的实际用途。我可以使用不同名称的函数。为什么我要尝试在我的应用程序中实现多态?
我对面向对象编程(OOP)很陌生。虽然我理解什么是多态(polymorphism),但我无法理解它的实际用途。我可以使用不同名称的函数。为什么我要尝试在我的应用程序中实现多态?
经典回答:想象一个基类 Shape
。它公开了一个 GetArea
方法。想象一下 Square
类、Rectangle
类和 Circle
类。不要创建单独的 GetSquareArea
、GetRectangleArea
和 GetCircleArea
方法,你只需在每个派生类中实现一个方法。你不需要知道使用的是哪个具体的 Shape
的子类,只需调用 GetArea
方法,你就可以得到你的结果,独立于具体类型。
看看这段代码:
#include <iostream>
using namespace std;
class Shape
{
public:
virtual float GetArea() = 0;
};
class Rectangle : public Shape
{
public:
Rectangle(float a) { this->a = a; }
float GetArea() { return a * a; }
private:
float a;
};
class Circle : public Shape
{
public:
Circle(float r) { this->r = r; }
float GetArea() { return 3.14f * r * r; }
private:
float r;
};
int main()
{
Shape *a = new Circle(1.0f);
Shape *b = new Rectangle(1.0f);
cout << a->GetArea() << endl;
cout << b->GetArea() << endl;
}
这里需要注意的一件重要事情是 - 你不需要知道你正在使用的类的确切类型,只需知道基本类型,你就能得到正确的结果。在更复杂的系统中,这非常有用。
学习愉快!
Circle *a = new Circle(1.0f);
然后调用 a->GetArea()
?为什么我们不能这样做?在什么情况下必须使用基础指针,即 Shape *ptr
?谢谢。 - skytree你有没有用+
把两个整数相加,再用+
把一个整数和一个浮点数相加?
你有没有记录x.toString()
来帮助你调试某些东西?
我认为你可能已经欣赏多态性,只是不知道它的名字。
// the following is pseudocode M'kay:
class apple;
class banana;
class kitchenKnife;
apple foo;
banana bar;
kitchenKnife bat;
apple *shoppingList = [foo, bar, bat]; // this is illegal because bar and bat is
// not of type apple.
解决方法:
class groceries;
class apple inherits groceries;
class banana inherits groceries;
class kitchenKnife inherits groceries;
apple foo;
banana bar;
kitchenKnife bat;
groceries *shoppingList = [foo, bar, bat]; // this is OK
此外,它使得处理项目列表更加直观。比如说所有杂货都实现了方法price()
,这样处理起来就很容易:
int total = 0;
foreach (item in shoppingList) {
total += item.price();
}
这两个特性是多态所做的核心。
多态的优点是客户端代码不需要关心方法的实际实现。 看下面的例子。 这里的CarBuilder不知道任何关于ProduceCar()的信息。一旦它被给定一个汽车列表(CarsToProduceList),它将生产所有必要的汽车。
class CarBase
{
public virtual void ProduceCar()
{
Console.WriteLine("don't know how to produce");
}
}
class CarToyota : CarBase
{
public override void ProduceCar()
{
Console.WriteLine("Producing Toyota Car ");
}
}
class CarBmw : CarBase
{
public override void ProduceCar()
{
Console.WriteLine("Producing Bmw Car");
}
}
class CarUnknown : CarBase { }
class CarBuilder
{
public List<CarBase> CarsToProduceList { get; set; }
public void ProduceCars()
{
if (null != CarsToProduceList)
{
foreach (CarBase car in CarsToProduceList)
{
car.ProduceCar();// doesn't know how to produce
}
}
}
}
class Program
{
static void Main(string[] args)
{
CarBuilder carbuilder = new CarBuilder();
carbuilder.CarsToProduceList = new List<CarBase>() { new CarBmw(), new CarToyota(), new CarUnknown() };
carbuilder.ProduceCars();
}
}
多态是面向对象编程的基础。它意味着一个对象可以作为另一个项目存在。那么一个对象如何变成另一个对象呢?通过以下方式实现:
其中一个主要优点是可以切换实现。比如你正在编写一个需要与数据库交互的应用程序,你定义了一个类来执行这些数据库操作,它被期望执行某些操作,例如添加、删除和修改。你知道数据库可以以许多方式实现,可以是与文件系统交互,也可以是与诸如MySQL等的RDBM服务器交互。因此,作为程序员,你会定义一个接口,例如...
public interface DBOperation {
public void addEmployee(Employee newEmployee);
public void modifyEmployee(int id, Employee newInfo);
public void deleteEmployee(int id);
}
现在你可能有多种实现方式,比如说我们有一种针对关系型数据库的实现,另一种是针对直接文件系统的实现。
public class DBOperation_RDBMS implements DBOperation
// implements DBOperation above stating that you intend to implement all
// methods in DBOperation
public void addEmployee(Employee newEmployee) {
// here I would get JDBC (Java's Interface to RDBMS) handle
// add an entry into database table.
}
public void modifyEmployee(int id, Employee newInfo) {
// here I use JDBC handle to modify employee, and id to index to employee
}
public void deleteEmployee(int id) {
// here I would use JDBC handle to delete an entry
}
}
public class DBOperation_FileSystem implements DBOperation
public void addEmployee(Employee newEmployee) {
// here I would Create a file and add a Employee record in to it
}
public void modifyEmployee(int id, Employee newInfo) {
// here I would open file, search for record and change values
}
public void deleteEmployee(int id) {
// here I search entry by id, and delete the record
}
}
public class Main {
public static void main(String[] args) throws Exception {
Employee emp = new Employee();
... set employee information
DBOperation dboper = null;
// declare your db operation object, not there is no instance
// associated with it
if(args[0].equals("use_rdbms")) {
dboper = new DBOperation_RDBMS();
// here conditionally, i.e when first argument to program is
// use_rdbms, we instantiate RDBM implementation and associate
// with variable dboper, which delcared as DBOperation.
// this is where runtime binding of polymorphism kicks in
// JVM is allowing this assignment because DBOperation_RDBMS
// has a "is a" relationship with DBOperation.
} else if(args[0].equals("use_fs")) {
dboper = new DBOperation_FileSystem();
// similarly here conditionally we assign a different instance.
} else {
throw new RuntimeException("Dont know which implemnation to use");
}
dboper.addEmployee(emp);
// now dboper is refering to one of the implementation
// based on the if conditions above
// by this point JVM knows dboper variable is associated with
// 'a' implemenation, and it will call appropriate method
}
}
您可以在许多地方使用多态的概念,一个实际的例子是:假设您正在编写图像装饰器,并且需要支持各种图像类型,例如jpg、tif、png等。因此,您的应用程序将定义一个接口并直接对其进行操作。然后,您将为每个jpg、tif、png等实现提供一些运行时绑定。
另一个重要的用途是,如果您使用Java,大多数情况下您都会使用List接口,这样您就可以在需要时使用ArrayList或其他接口,以满足您的应用程序增长或需求变化的要求。
多态性允许您编写使用对象的代码。然后,您可以稍后创建新类,您现有的代码可以在不进行任何修改的情况下使用。
例如,假设您有一个函数Lib2Groc(vehicle)
,它将车辆从图书馆指导到杂货店。它需要告诉车辆向左转,因此它可以在车辆对象上调用TurnLeft()
等其他操作。然后,如果有人后来发明了一种新型车辆,比如气垫船,它可以被Lib2Groc
使用而无需进行任何修改。
我想有时候对象是动态调用的。在经典的形状多边形的例子中,您不确定对象是否为三角形、正方形等。
因此,为了摆脱所有这些问题,我们只需调用派生类的函数,并假设会调用动态类之一。
您不需要关心它是正方形、三角形还是矩形。您只需要关心面积。因此,根据传递的动态对象,将调用getArea方法。
多态操作最显著的好处之一是能够扩展功能。 您可以使用相同的操作,而不更改现有的接口和实现,只因为您需要一些新的东西。
我们从多态性中想要的一切 - 就是简化我们的设计决策,使我们的设计更具可扩展性和优雅性。 您还应该注意开闭原则(http://en.wikipedia.org/wiki/Open/closed_principle)和SOLID(http://en.wikipedia.org/wiki/Solid_%28Object_Oriented_Design%29),这些可以帮助您理解关键的面向对象原则。
P.S. 我认为您在谈论“动态多态性”(http://en.wikipedia.org/wiki/Dynamic_polymorphism),因为还有“静态多态性”(http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism)这样的东西。
你不需要多态。
直到你需要它。
然后它太棒了。
一个你将会遇到很多次的简单答案:
有人需要遍历一些东西的集合。比如他们要求一个类型为MySpecializedCollectionOfAwesome的集合。但你一直在处理类型为List<T>的Awesome实例。所以,现在,你需要创建一个MSCOA的实例,并用你List<T>中所有Awesome实例来填充它。这真让人头疼,对吧?
但是,如果他们要求一个IEnumerable<Awesome>,你就可以给他们很多个Awesome的集合。比如你可以给他们一个数组(Awesome[])或一个列表(List<Awesome>)或一个ObservableCollection of Awesome或其他任何你保存你的Awesome并且实现了IEnumerable<T>接口的东西。
多态的威力使你能够保持类型安全,同时又足够灵活,让你可以使用一个实例进行许多不同的操作,而不必创建特别处理此类型或那个类型的大量代码。
选项卡应用程序
对我来说,一个好的应用程序是在选项卡应用程序中具有通用按钮(适用于所有选项卡)- 即使我们使用的浏览器也实现了多态性,因为它不知道我们在编译时(换句话说,在代码中)使用的选项卡。它总是在运行时(就是现在!当我们使用浏览器时。)确定。