关于oop:多态性的真正意义(用途)是什么

What is the real significance(use) of polymorphism

我是新手。虽然我知道什么是多态性,但我不能真正使用它。我可以有不同名称的函数。为什么我要尝试在我的应用程序中实现多态性。


经典答案:想象一个基类Shape。它公开了一种GetArea方法。想象一个Square类,一个Rectangle类,一个Circle类。不是创建单独的GetSquareAreaGetRectangleAreaGetCircleArea方法,而是在每个派生类中只实现一个方法。你不需要知道你使用的Shape的确切子类,你只需要调用GetArea,就可以得到你的结果,与具体类型无关。

请看一下此代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#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;
}

这里需要注意的一件重要的事情是-你不必知道你所使用的类的确切类型,只需要知道基本类型,你就能得到正确的结果。这在更复杂的系统中也非常有用。

学习愉快!


你有没有用+加两个整数,然后用+加一个整数到一个浮点数?

您是否登录过x.toString()来帮助您调试某些东西?

我想你可能已经很欣赏多态性了,只是不知道它的名字。


在严格类型化语言中,多态性对于拥有不同类型的对象的列表/集合/数组非常重要。这是因为列表/数组本身的类型是只包含正确类型的对象。

例如,假设我们有以下内容:

1
2
3
4
5
6
7
8
9
10
11
// 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.

解决这个问题:

1
2
3
4
5
6
7
8
9
10
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()的方法,处理起来很容易:

1
2
3
4
int total = 0;
foreach (item in shoppingList) {
    total += item.price();
}

这两个特性是多态性的核心功能。


多态性的优点是客户端代码不需要关心方法的实际实现。看看下面的例子。在这里,Carbuilder对ProduceCar()一无所知。一旦它得到一个汽车列表(CarstoProduceList),它将相应地生产所有必要的汽车。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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();
    }
}

多态性是面向对象编程的基础。这意味着一个对象可以作为另一个项目来拥有。那么,在对象上如何能够成为其他对象,它可以通过以下方式实现

  • 遗传
  • 重写/实现父类行为
  • 运行时对象绑定
  • 它的一个主要优点是交换机实现。假设您正在对需要与数据库对话的应用程序进行编码。您碰巧定义了一个类,它为您执行这个数据库操作,并且它预期会执行一些操作,比如添加、删除、修改。您知道数据库可以通过多种方式实现,它可以与文件系统或RDBM服务器(如mysql等)进行通信。因此,作为程序员,您将定义一个可以使用的接口,例如…

    1
    2
    3
    4
    5
    public interface DBOperation {
        public void addEmployee(Employee newEmployee);
        public void modifyEmployee(int id, Employee newInfo);
        public void deleteEmployee(int id);
    }

    现在您可能有多个实现,假设我们有一个用于RDBMS,另一个用于直接文件系统。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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
        }
    }

    让我们实现文件系统数据库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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
        }
    }

    让我们看看主管道如何在两者之间切换。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    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、PGN等中的每一个,您都有一些不同实现的运行时绑定。

    另一个重要用途是,如果您使用Java,大多数时候您将在列表接口上工作,以便在应用程序增长或需求改变时,可以使用ARRAYList或其他接口。


    多态操作最显著的好处之一是扩展能力。您可以使用相同的操作,而不更改现有的接口和实现,因为您面临着一些新事物的需求。

    我们只需要多态性来简化我们的设计决策,使我们的设计更具可扩展性和优雅性。您还应该注意开放-关闭原则(http://en.wikipedia.org/wiki/open/closed-u原则)和Solid(http://en.wikipedia.org/wiki/solid-28面向对象的u设计%29),它们可以帮助您理解主要的OO原则。

    P.S.我认为你说的是"动态多态性"(http://en.wikipedia.org/wiki/dynamic_多态性),因为有"静态多态性"(http://en.wikipedia.org/wiki/template_metaprogramming_static_多态性)之类的东西。


    多态性允许您编写使用对象的代码。然后,您可以稍后创建新的类,您的现有代码可以在不进行修改的情况下使用这些类。

    例如,假设您有一个函数Lib2Groc(vehicle),它将车辆从图书馆引导到杂货店。它需要告诉车辆左转,这样它就可以在车辆对象上调用TurnLeft()。然后,如果有人后来发明了一种新的飞行器,比如气垫船,它可以被Lib2Groc使用而不需要修改。


    选项卡式应用程序

    对我来说,一个好的应用程序是选项卡应用程序中的通用按钮(对于所有选项卡),即使我们使用的浏览器也在实现多态性,因为它不知道我们在编译时使用的选项卡(换句话说,在代码中)。它总是在运行时确定(现在!当我们使用浏览器时。)


    我想有时候对象是动态调用的。你不确定物体是否是一个三角形,正方形等在一个经典的形状多边形。例子。

    所以,为了把所有这些都抛在脑后,我们只调用派生类的函数,并假设将调用动态类中的一个。

    你不会在意它是正方形、三角形还是矩形。你只关心这个地区。因此,将根据传递的动态对象调用GetArea方法。


    你不需要多态性。

    直到你这样做。

    那么它的金块棒极了。

    简单的答案,你会处理很多次:

    有人需要检查一些东西。假设他们要求一个类型为myspecializedcollectionofawesome的集合。但你一直在处理你的"超人名单"实例。所以,现在,您必须创建一个mscoa实例,并用您列表中的所有优秀实例填充它。屁股疼得厉害,对吧?

    好吧,如果他们要一个IEnumerable,你可以给他们一个集合的Awesome。你可以给他们一个数组(Awesome[])或者一个列表(List)或者一个Awesome的可观察集合,或者任何你让Awesome保持在实现IEnumerable中的东西。

    多态性的强大功能使您能够确保类型安全,同时也足够灵活,您可以使用许多不同的方法来使用实例,而无需创建大量专门处理此类型或该类型的代码。