C#编程(二十五)----------接口
接口
如果一个类派生自一个接口,声明这个类就会实现某些函数.并不是所有的面向对象的语言都支持接口.
例如,有一个接口:IDispoable,包含一个方法Dispose(),该方法又类实现,用于清理代码:
public interface IDisposable
{
void Dispose();
}
上述代码说明,声明接口在语法上与声明抽象类完全相同,但不允许提供接口中任何成员的实现方式.一般情况下,接口只能包含方法,属性,索引器和事件的声明.
不能实例化接口,他只能包含mount成员的二千名.接口既不能有构造函数,也不能有字段.接口定义也不允许包含运算符重载.
在接口定义中还不允许声明关于成员的修饰符.接口成员总是共有的,不能声明为虚拟或静态.如果需要,就有实现的类来声明,因此最好实现执行的类来声明访问修饰符.
例如上面的IDisposable接口中的Disposable方法.
class SomeClass : IDisposable
{
public void Disposable()
{
}
}
在这个例子中,如果SomeClass派生自IDisposable类,但没有实现Disposable(),就会得到一个编译错误,因为该类破坏了实现的IDisposable的一致协定.当然,编译器允许类有一个不派生自IDisposable类的Disposable()方法.问题是其他代码无法识别出SomeClass类支持的IDisposable特性.
定义和实现接口
下面开发一个遵循接口继承规范的小例子说明如何定义和实现接口.编写代码,最终允许在银行账户之间进行计算机转账业务.许多公司可以实现银行账户,但他们都是彼此赞同表示银行账户的所有类都实现接口IBankAccount.该接口包含一个用于存款的方法和一个返回余额的属性.
我们的目的是允许银行账户彼此通信,以便在账户之间进行转账业务.
首先定义接口:
public interface IBankAccount
{
void PayIn(decimal amount);
bool Withdraw(decimal amount);
decimal Balance
{
get;
}
}
注意接口的名称为IBankAccount.接口的名称通常是以字母I开头,以便知道这是一个借口.
现在编写表示银行账户的类.这些类不必彼此相关,他们可以是完全不同的类.但他们都表示银行账户,因为他们都实现了IBankAccount接口.
第一个类:
public class SavaAccount:IBankAccount
{
private decimal balance;
public void PayIn(decimal amount)
{
balance += amount;
}
public bool Withdraw(decimal amount)
{
if (balance>=amount)
{
balance -= amount;
return true;
}
Console.WriteLine("Withdrawal attempt failed. "); ;
return false;
}
public decimal Balance
{
get
{
return balance;
}
}
public override string ToString()
{
return string.Format("Venus Bank Saver : Balance ={0,6}:C",balance);
}
}
这个类包含了一个私有字段balance,当存款或取款时就调整这个字段.如果因为账户中的金额不足而取款失败,就会显示一条错误信息.
接下来看这个类的声明:
public class SavaAccount : IBankAccount
SavaAccount 派生自一个接口IBankAccount,我们没有明确指出任何其他积累.另外,从接口中派生完全独立与类中派生.
SavaAccount 派生自IBankAccount,表示它获得了IBankAccount的所有成员,但接口实际上并没有实现其方法,所以SavaAccount 必须提供这些方法的所有实现代码.如果缺少实现代码,编译器就会产生错误.
接口仅表示其成员的存在性,类负责确定这些成员是虚拟的还是抽象的(但只有在类本身是抽象的,这些函数才能是抽象)
另一个类:
public class GoldAccount : IBankAccount
{内容和SavaAccount类一样}
然后再Main()方法中:
static void Main(string[] args)
{
IBankAccount venusAccount = new SvaAccount();
IBankAccount jupiterAccount = new GoldAccount();
venusAccount.PayIn(200);
venusAccount.Withdraw(100);
Console.WriteLine(venusAccount.ToString());
jupiterAccount.PayIn(500);
jupiterAccount.Withdraw(600);
jupiterAccount.Withdraw(100);
Console.WriteLine(jupiterAccount.ToString()); ;
Console.ReadKey();
}
输出为:
Venus Bank Saver : Balance = 100$:
Withdrawal attempt failed.
jupit Bank Saver : Balance = 400$:
以上代码中,要点是把两个引用声明变量为IBankAccount引用的方式.这表示他们可以指向实现这个借口的任何类的任何实例.但我们只能通过这些引用调用接口的一部分方法----如果要调用由类实现的但不在接口中的方法,就需要把引用强制转换为合适的类型.我们调用了ToString(),但没有进行任何显示的强制转换,这是因为ToString()是一个object方法,因此C#编译器知道任何类都支持这个方法(换句话说,从人和接口到object的数据类型强制转换为隐式的)
接口引用完全可以看做是类引用----但接口引用的强大之处在于,可以引用任何实现该接口的类.例如,我们可以构造接口数组,其中数组的每个元素都是不同的类:
IBankAccount[] accounts = new IBankAccount[2];
accounts[0] = new SvaAccount();
accounts[1] = new GoldAccount();
但是如果出现一个没有继承该接口的类就出现错误:
例如:
accounts[0] = new SomeClassAccount();这是错误的.
派生的接口
接口可以彼此派生,其方式与类的继承方式相同.下面通过定义一个新的接口ITransferBankAccount来说明这个概念,该接口的功能与IBankAccount相同,只是定义了一个方法,把资金转到另一个账户上.
定义该接口:
interface ITransferBankAccount:IBankAccount
{
bool TransferTo(IBankAccount destination, decimal amount);
}
因为ITransferBankAccount派生自IBankAccount,所以它拥有IBankAccount的所有成员和它自己的成员.这表示实现(派生自)ITransferBankAccount的任何类都必须实现IBankAccount的所有方法和在ITransferBankAccount中定义的新方法TransferTo().没有实现这些所有的方法就会报错.
注意TransferTo()方法对于目标账户使用了IBankAccount接口引用.这说明了接口的用途:在实现并调用这个方法是,不必知道转账的对象类型,只需要知道该对象实现了IBankAccount即可.
下面说明ITransferBankAccount:假定Jupiter还提供了一个当前账户.CurrentAccount类的大多数实现代码与SvaAccount和GoldAccount的实现代码相同.
public class CurrentAccount:ITransferBankAccount
{
private decimal balance;
public void PayIn(decimal amount)
{
balance += amount;
}
public bool Withdraw(decimal amount)
{
if (balance >= amount)
{
balance -= amount;
return true;
}
Console.WriteLine("Withdrawal attempt failed. "); ;
return false;
}
public decimal Balance
{
get
{
return balance;
}
}
public override string ToString()
{
return string.Format("jupit Bank Current Account : Balance ={0,6}$:", balance);
}
public bool TransferTo(IBankAccount destination, decimal amount)
{
bool result;
result = Withdraw(amount);
if (result)
{
destination.PayIn(amount);
}
return result;
}
}
Main()函数的内容:
IBankAccount venusAccount = new SvaAccount();
ITransferBankAccount jupiterAccount = new CurrentAccount();
venusAccount.PayIn(200);
jupiterAccount.PayIn(500);
jupiterAccount.TransferTo(venusAccount, 100);
Console.WriteLine(venusAccount.ToString());
Console.WriteLine(jupiterAccount.ToString());
Console.ReadKey();
输出结果为:
Venus Bank Saver : Balance = 300$:
jupit Bank Current Account : Balance = 400$:
表示转账成功
C#编程(二十五)----------接口的更多相关文章
- Python学习日记(二十五) 接口类、抽象类、多态
接口类 继承有两种用途:继承基类的方法,并且做出自己的改变或扩展(代码重用)和声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子 ...
- 策略模式 Strategy 政策Policy 行为型 设计模式(二十五)
策略模式 Strategy 与策略相关的常见词汇有:营销策略.折扣策略.教学策略.记忆策略.学习策略.... “策略”意味着分情况讨论,而不是一概而论 面对不同年龄段的人,面对不同的商品,必然将会 ...
- WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇]
原文:WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇] 在[WS标准篇]中我花了很大的篇幅介绍了WS-MEX以及与它相关的WS规范:WS-Policy.WS-Tra ...
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...
- C#学习基础概念二十五问
C#学习基础概念二十五问 1.静态变量和非静态变量的区别?2.const 和 static readonly 区别?3.extern 是什么意思?4.abstract 是什么意思?5.internal ...
- 剑指Offer(二十五):复杂链表的复制
剑指Offer(二十五):复杂链表的复制 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/bai ...
- 使用Typescript重构axios(二十五)——文件上传下载进度监控
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 学习笔记:CentOS7学习之二十五:shell中色彩处理和awk使用技巧
目录 学习笔记:CentOS7学习之二十五:shell中色彩处理和awk使用技巧 25.1 Shell中的色彩处理 25.2 awk基本应用 25.2.1 概念 25.2.2实例演示 25.3 awk ...
- 《手把手教你》系列技巧篇(二十五)-java+ selenium自动化测试-FluentWait(详细教程)
1.简介 其实今天介绍也讲解的也是一种等待的方法,有些童鞋或者小伙伴们会问宏哥,这也是一种等待方法,为什么不在上一篇文章中竹筒倒豆子一股脑的全部说完,反而又在这里单独写了一篇.那是因为这个比较重要,所 ...
- Bootstrap <基础二十五>警告(Alerts)
警告(Alerts)以及 Bootstrap 所提供的用于警告的 class.警告(Alerts)向用户提供了一种定义消息样式的方式.它们为典型的用户操作提供了上下文信息反馈. 您可以为警告框添加一个 ...
随机推荐
- java 标准异常
一.Throwable这个Java类被用来表示任何可以作为异常被抛出的类.Throwable对象可分为两种类型(从Throwable继承而得到的类型): 1.) Error用来表示编译时和系统错误 2 ...
- python爬虫-基础
所谓网页抓取,就是把URL地址中指定的网络资源从网络流中读取出来,保存到本地. 类似于使用程序模拟IE浏览器的功能,把URL作为HTTP请求的内容发送到服务器端, 然后读取服务器端的响应资源. 1.浏 ...
- yum安装tomcat
http://www.cnblogs.com/liaolongjun/p/5638740.html http://www.awspack.com/os/linux/yum-install-tomcat ...
- python标准模块(下)
Python 系统标准模块(shutil.logging.shelve.configparser.subprocess.xml.yaml.自定义模块) 目录: shutil logging模块 she ...
- finall和set和构造方法的参数意义
package demo04; /* * 形状 */public abstract class Shape { // 求周长 public abstract double getGrith(); // ...
- pycharm+PyQt5+python最新开发环境配置
Python 3.6https://www.python.org/downloads/windows/========================================PyQt5 pip ...
- 如何安装pycharm
Ubuntu系统安装PyCharm教程(详细图文) 参考(http://jingyan.baidu.com/article/60ccbceb4e3b0e64cab19733.html)
- 局域网内其他主机如何访问运行在宿主机的虚拟机中的Django项目(转)
局域网内其他主机如何访问运行在宿主机的虚拟机中的Django项目 1.在宿主机cmd中查看宿主机的ip(注意区分主机中虚拟机的ip) 我连的是无线,IP如下 2.在Django项目的mysit ...
- 2013-2014 ACM-ICPC Brazil Subregional Programming Contest 题解
[题目链接] 这场比赛题面英文都好长... ... A - Zero or One 模拟. #include <bits/stdc++.h> using namespace std; in ...
- 025.Zabbix之SNMP监控
一 SNMP介绍及配置 1.1 SNMP介绍参考其他笔记 1.2 SNMP配置 [SW1]int vlan 1 [SW1-Vlanif1]ip address 172.24.8.13 24 [SW1- ...