简体   繁体   English

为什么要使用基类引用创建对象?

[英]Why should I want to create an object with base class reference?

    public class BaseClass
    {
        public virtual void Display()
        {
            Console.WriteLine("I am Base Class");
        }

        public void BaseClassMethod()
        {
            Console.WriteLine("I am Base Class Method");
        }
    }

    public class DerivedClass : BaseClass
    {
        public override void Display()
        {
            Console.WriteLine("I am Derived Class");
        }

        public void DerivedClassMethod()
        {
            Console.WriteLine("I am Derived Class Method");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            BaseClass bc = new BaseClass();
            bc.Display();
            bc.BaseClassMethod();

            Console.WriteLine("--------------");

            DerivedClass dc = new DerivedClass();
            dc.Display();
            dc.BaseClassMethod();
            dc.DerivedClassMethod();

            Console.WriteLine("--------------");

            BaseClass bc2 = new DerivedClass();
            bc2.Display();
            bc2.BaseClassMethod();
            //bc2.DerivedClass();  --> I can't reach b2.DerivedClass() method

            Console.ReadLine();
        }
    }

Hi everyone. 嗨,大家好。 I am trying to clear my mind about Why and where would I want to create and use derived class object from base class reference. 我试图清除我的想法,以及为什么要在基类引用中创建和使用派生类对象。 I know how virtual works. 我知道虚拟是如何工作的。 I know derived class is a base class and I can override virtual methods. 我知道派生类是基类,可以覆盖虚方法。 I can reach non virtual methods in base class. 我可以在基类中达到非虚拟方法。 But I want to know where could and why would I want to use this style of object creation. 但是我想知道在哪里以及为什么要使用这种对象创建样式。 Like in my last part of the example code; 就像在示例代码的最后一部分一样;

BaseClass bc2 = new DerivedClass();

I can't reach derived class methods so I cant use derived class methods. 我无法到达派生类方法,因此无法使用派生类方法。 But it is still derived class because of the new DerivedClass. 但是由于新的DerivedClass,它仍然是派生类。 If I use normal DerivedClass d = new DerivedClass(); 如果我使用普通的DerivedClass d = new DerivedClass(); style, I can use both class methods. 样式,我可以同时使用两个类方法。 I just cant find any reason and situation I would want to use this style. 我只是找不到我要使用此样式的任何原因和情况。 I would be glad if anyone show me in which situation I have to use derived class object from base class reference so I can understand this style is exist in language. 如果有人告诉我在什么情况下我必须使用基类引用中的派生类对象,以便可以理解这种样式存在于语言中,我将非常高兴。 I want to know WHY, I am not asking why this isn't working or something like that. 我想知道为什么,我不是在问为什么这不起作用或类似的问题。 Just want to know situations. 只想知道情况。 Thank you. 谢谢。

There are two main usages: 主要有两种用法:

1) Collections of multiple types 1)多种类型的集合

Lets change your example a little bit 让我们稍微改变一下你的例子

public class Shape
{
    public virtual void Display()
    {
        Console.WriteLine("I am a Shape");
    }

    public void BaseClassMethod()
    {
        Console.WriteLine("I am Base Class Method");
    }
}

public class Square : Shape
{
    public override void Display()
    {
        Console.WriteLine("I am Square");
    }

    public void DerivedClassMethod()
    {
        Console.WriteLine("I am Derived Class Method");
    }
}



public class Circle : Shape
{
    public override void Display()
    {
        Console.WriteLine("I am Circle");
    }
}

class Program
{
    static void Main(string[] args)
    {
        List<Shape> shapes = new List<Shape();
        shapes.Add(new Square());
        shapes.Add(new Circle());

I have a list that can hold Circles, Squares, and generic Shapes all in a single collection. 我有一个列表,可以在一个集合中保存所有的圆形,正方形和通用形状。

2) Polymorphism 2)多态

Continuing on from the previous code 继续上一个代码

         foreach(Shape shape in shapes)
         {
             shape.Display();
         }

we don't know what kind of Shape the variable shape is, however we do know that whatever kind it is it will have a Display() method we can call and it will show the correct information. 我们不知道可变shape是哪种Shape ,但是我们知道无论哪种Shape都有一个Display()方法可以调用,并且它将显示正确的信息。

Polymorphism is useful when you need to call a function on something but you don't know the specific type that something will be because you are pulling a collection of base types like above, or you want to write a function that can take in any kind of Shape because the function does not need to know the specific kind to do it's work. 当您需要在某物上调用函数但不知道某物的特定类型时,多态性很有用,因为您要提取上面的基本类型集合,或者您想编写一个可以接受任何形式的函数Shape的功能,因为该功能不需要知道具体的种类即可完成工作。

    public static void LogDisplay(Shape shape)
    {
         Console.WriteLine("I am about to call shape.Display()");
         shape.Display();
         Console.WriteLine("I am just called shape.Display()");
    }

My favorite example, because people can understand the use, is logging. 我最喜欢的示例是日志记录,因为人们可以理解其用法。 Imagine I create a website. 想象一下,我创建了一个网站。 When I'm developing the site, I want to log to my file system, because it's easy to access. 在开发站点时,我想登录到我的文件系统,因为它很容易访问。 When I deploy the website, I want to log to the event log, because maybe I don't have direct access to the file system on that machine. 部署网站时,我想登录到事件日志,因为也许我无法直接访问该计算机上的文件系统。

However, I only want to change where things are logged, I want the base class to structure how the actual text looks. 但是,我只想更改记录的位置,我希望基类构造实际文本的外观。 So I have my base class that formats text: 所以我有格式化文本的基类:

public abstract class BaseLogger
{
     public abstract void LogException(Exception ex);
     public abstract void LogUserMessage(string userMessage);

     protected string GetStringFromException(Exception ex)
     {
        //....
     }

     protected string GetStringFromUserMessage(string userMessage)
     {
        //....  
     }
}

Now I can have a class that logs to the File System: 现在,我可以拥有一个登录到文件系统的类:

public class FileLogger : BaseLogger
{
    public FileLogger(string filename)
    {
        //initialize the file, etc
    }

    public override void LogException(Exception ex)
    {
        var string = GetStringFromException(ex);
        File.WriteAllLines(...);
    }

    public override void LogException(Exception ex)
    {
        var string = GetStringFromUserMessage(ex);
        File.WriteAllLines(...);
    }
}

and my class that logs to the Event Log: 和我的类记录到事件日志:

public class EventLogger : BaseLogger
{  
    public EventLogger()
    {
        //initialize the eventlog, etc
    }

    public override void LogException(Exception ex)
    {
        var string = GetStringFromException(ex);
        EventLog.WriteEntry(...);
    }

    public override void LogException(Exception ex)
    {
        var string = GetStringFromUserMessage(ex);
        EventLog.WriteEntry(...);
    }
}

Now in my program, I only care that I have a BaseLogger when I inject one into my classes. 现在,在我的程序中,当我将BaseLogger注入类时,我只关心自己有一个BaseLogger The implementation details are irrelevant, I just know that I can LogException and LogUserMessage no matter what I'm using. 实现细节无关紧要,我只知道无论使用什么,都可以使用LogExceptionLogUserMessage

When I'm using the logger I benefit from not caring which derived class I use . 使用记录器时,无需关心 使用的哪个派生类,我会从中受益 That's the benefit of treating each derived class like a base class. 这是将每个派生类都视为基类的好处。 I can swap them out without my program caring. 我可以将它们换出而无需担心程序。

There are many reasons to do this, mostly to do with code re-usability and extensiblity, which in other words, to make a small change or enhancement easily without needing to rewrite a whole lot. 这样做的原因有很多,主要与代码的可重用性和可扩展性有关,换句话说,无需更改大量代码即可轻松进行小的更改或增强。

A real world example (which happens frequently) is the case where you have different customers using your software which may require you to support different databases (or even different table structures). 一个真实的例子(经常发生)是您有不同的客户使用您的软件,这可能需要您支持不同的数据库(甚至不同的表结构)。 So in order to do that, you can derive implementations from a common base class, and vary in the implementation details without affecting the rest of the program. 因此,为了做到这一点,您可以从通用基类派生实现,并在不影响程序其余部分的情况下改变实现细节。

This also follows the design principle "Program to an 'interface', not an 'implementation'" which is explained in the GoF design pattern book 这也遵循了设计原则“编程到'接口',而不是'实现'”,该原则在GoF设计模式手册中进行了解释。

public abstract class ProviderBase
{
    public abstract Employee[] GetAllEmployees();
}

public class MySqlProvider:ProviderBase
{
    public override Employee[] GetAllEmployees()
    {
        string select = "select * from employees";

        //query from mysql ...
    }

}

public class MsSqlProvider : ProviderBase
{
    public override Employee[] GetAllEmployees()
    {
        string select = "select * from user u left join employee_record e on u.id=e.id";

        //query from mysql ...
    }
}

Then in the main program you may be able to change the type of database implementation by configuration or Dependency Injection 然后,在主程序中,您可以通过配置或依赖注入来更改数据库实现的类型

ProviderBase provider = null;
if(databaseType == "MySql")
{
    provider = new MySqlProvider();
}
else if (databaseType == "MsSql")
{
    provider = new MsSqlProvider();
}

var employees = provider.GetAllEmployees();
//do something

I believe a lot of the reasoning behind the availability of using derived classes has to do with minimizing repeated code. 我相信,使用派生类的背后许多原因都与减少重复代码有关。

To reference a real life example... If I was to ask you to describe the attributes and abilities of a car, and then was to ask you to do the same for an electric car, you would find that much of the attributes and abilities are shared by both. 举一个现实的例子...如果我要您描述一辆汽车的属性和能力,然后要您对一辆电动汽车做同样的事情,您会发现很多属性和能力两者共享。 So instead of having it be two completely separate classes, it would be more efficient to create the base class Car, and derive electricCar from that. 因此,与其创建两个完全独立的类,不如创建基类Car并从中派生ElectricCar效率更高。 Then you will only need to account for the specific differences of the electric car within the derived class, and all the shared attributes and abilities will carry over. 然后,您只需要考虑派生类中电动汽车的特定差异,所有共享的属性和功能都会保留下来。

Hope this helps you understand the usefulness of base classes and derived classes. 希望这可以帮助您了解基类和派生类的有用性。 Very oversimplified but I feel it may help you grasp the concept! 过于简化了,但我认为它可以帮助您掌握概念!

The main reason to use a base class is reusability and polymorphism 使用基类的主要原因是可重用性多态性

So you could create the class depending on a condition: 因此,您可以根据条件创建类:

BaseClass bc
if(case1)
    bc = new DerivedClass1();
else
    bc = new DerivedClass2();

In the following application you can use bc even if you don't know what kind of derived class it is at compile time. 在以下应用程序中,即使您在编译时不知道它是哪种派生类,也可以使用bc You can pass it eg to other functions and call the overridden methode: 您可以将其传递给其他函数,然后调用重写的方法:

bc.Display();

Derived class methods can only be used when you know what kind of derived class you actual have. 仅当您知道实际具有哪种派生类时,才能使用派生类方法。 Then you can do a conversion. 然后,您可以进行转换。

DerivedClass1 dc = bc as DerivedClass1;
dc.DerivedClassMethod()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么要参考派生类创建基类对象 - Why would one create a Base Class object with reference to the Derived Class 为什么我要在基类变量中实例化一个对象? - Why would I want to instantiate an object in a base class variable? 我们可以创建指向基础对象的派生类引用 - Can we create derived class reference which points to base object 什么是基类构造函数,为什么要使用它? (带有示例) - What is a base class constructor and why would I want to use it? (with Example) 为什么我要将 class2 的引用放入 class1 的对象中? - Why would I put a reference of class2 into an object of class1? 如何在基类中创建对象的克隆? - How do I create clone of object in base class? 为什么我不能隐式地将此对象强制转换为类引用 - Why can't I implicitly cast this object to a class reference 为什么我应该使用对基类的引用,我无法理解区别 - Why should I use references to a base class, I can't understand the difference 我可以引用扩展方法/参数而不必从返回的基类对象进行强制转换 - Can can I reference extended methods/params without having to cast from the base class object returned 为什么我不能将基类引用转换为派生类实现的变量接口? - Why can't I cast base reference to a variant interface implemented by derived class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM