我很难理解C#中接口的使用。 这可能是因为我来自Python,而该Python并未在其中使用。
我不理解其他解释,因为它们不能完全回答我有关接口的问题。例如The purpose of interfaces continued
据我了解,Interfaces告诉类它可以做什么,而不是怎么做。这意味着在某个时候必须告诉类如何执行方法。
如果是这种情况,接口的意义何在?为什么不只在类中定义方法?
我看到的唯一好处是清楚地说明了哪些类可以/不能做什么,但是以不使用DRY代码为代价?
我知道Python不需要接口,我认为这限制了我的理解,但无法完全弄清楚为什么。
答案 0 :(得分:1)
它在python中以抽象类的形式使用(通常)。
目的各不相同,在Java中,它们解决了多重继承问题;在python中,它们充当了2个类之间的契约。
A类做某事,而其中的一部分则涉及B类。B类可以通过多种方式实现,因此,不必使10个不同的类和HOPE正确使用,而应使它们从抽象类继承(接口),并确保它们必须实现定义为抽象的所有方法。 (请注意,如果它们不采用任何一种在构建时崩溃的方法,则当您安装软件包时,而不是在中,大型项目中非常重要的运行时)。
您还知道实现这些方法的ANY类将与使用它的类一起使用。这听起来很琐碎,但由于它意味着您可以将部分代码外包,并且可以连接其余的代码并与之一起工作,因此业务方面对此并不满意。
据我了解,Interfaces告诉类它可以做什么,而不是怎么做。这意味着在某个时候必须告诉类如何执行方法。
实际上,他们告诉它必须做什么,以及我们不关心他们如何做。
如果是这种情况,接口的意义何在?为什么不只在类中定义方法?
这不是重点,但是是的,您绝对需要在继承自接口的类中定义方法。
让我们给您一个更具体的例子。
想象一下,您有一个运行某些任务的python框架。这些任务可以在本地运行(在运行python框架的同一台计算机上),它们可以在分布式系统上运行,通过将它们提交给某个中央调度程序,它们可以在docker容器中运行,在Amazon Web services上。你明白了。
您所需要的只是一个具有run_task方法的接口(python中的抽象类),具体取决于您使用哪个。
例如:
class Runner:
__metaclass__ = abc.ABCMeta
@abstractmethod
def run_task(self, task_command):
return
class LocalRunner(Runner):
def run_task(self, task_command):
subprocess.call(task_command)
class SlurmRunner(Runner):
def run_task(self, task_command):
subprocess.call('sbatch ' + task_command)
现在很重要,因为您可能会问为什么^ $ ^ $%我需要所有这些 并发症? (如果yopur项目足够小,您可能不会知道,但是根据您几乎必须开始使用这些功能的大小,会有一个断点。)
仅使用运行器的类需要了解接口,例如您有一个Task类,该类可以将任务的执行委托给TaskRunner,因为您不必在乎哪个实现,它们在某种意义上是多态的。
class Task:
def __init__(self, task_runner):
self.task_runner = task_runner
self.task_command = 'ls'
def run_this_task(self):
self.task_runner.run_task(self.task_command)
并且,如果您是老板可以告诉您的一些程序员,我需要一个新类在AWS上执行命令,将其分配给命令,并实现task_runner方法,那么您无需了解其他任何内容代码,您可以将其作为一个完全隔离的部分来实现(这是外包部分,现在您可以有100个人指定100个不同的部分,他们不需要了解任何代码,只需要了解接口即可)
答案 1 :(得分:0)
class Cat:
def meow(self):
print('meow')
def feed(cat):
cat.moew() # he thanks the owner
tom = Cat('Tom')
feed(tom)
C Sharp具有静态类型系统。编译器需要知道该类具有哪些方法。这就是为什么我们必须为每个变量设置类型的原因:
def feed(cat: Cat):
cat.moew() # he thanks the owner
但是,如果我们必须编写代码并且不知道变量必须具有的确切类型怎么办?
def feed(it):
it.thank_owner()
此外,我们必须假设我们的函数将用于各种类。别忘了我们必须让编译器知道每个变量的类型!该怎么办?解决方案:
class Pet: # an interface
def thank_owner(self):
raise NotImplementedError()
def feed(it: Pet):
it.thank_owner()
但是与Cat怎么办?解决方案:
class Cat(Pet): # inherits the interface Pet
def thank_owner(self):
print('meow') # or self.meow() if we want to avoid big changes and follow DRY rule at the same time
tom = Cat('Tom')
feed(tom)
现在,我们可以轻松添加新宠物。我们不必重写代码。
class Dog(Pet):
def thank_owner(self):
print('woof')
beethoven = Dog('Beethoven')
feed(beethoven) # yes, I use the same function. I haven't changed it at all!
请注意,我们在feed()
和Pet
之后创建了此类。之前编写代码时,我们不要考虑Dog
,这一点很重要。我们对此并不感到好奇。但是,当我们需要扩展代码时,我们没有遇到任何问题。