当前位置: 首页 > news >正文

龙泉网站建设wordpress 博主

龙泉网站建设,wordpress 博主,VPS如何做镜像网站,西安软件公司排行榜在面向对象编程中,抽象类和接口是两个经常被用到的语法概念,是面向对象四大特性,以及很多设计模式、设计思想、设计原则编程实现的基础。比如,我们可以使用接口来实现面向对象的抽象特性、多态特性和基于接口而非实现的设计原则,使用抽象类来实现面向对象的继承特性和模板设计模…在面向对象编程中,抽象类和接口是两个经常被用到的语法概念,是面向对象四大特性,以及很多设计模式、设计思想、设计原则编程实现的基础。比如,我们可以使用接口来实现面向对象的抽象特性、多态特性和基于接口而非实现的设计原则,使用抽象类来实现面向对象的继承特性和模板设计模式等等。不过,并不是所有的面向对象编程语言都支持这两个语法概念,比如, C这种编程语言只支持抽象类,不支持接口;而像Python这样的动态编程语言,既不支持抽象类,也不支持接口。尽管有些编程语言没有提供现成的语法来支持接口和抽象类,我们仍然可以通过一些手段来模拟实现这两个语法概念。这两个语法概念不仅在工作中经常会被用到,在面试中也经常被提及。比如“接口和抽象类的区别是什么什么时候用接口?什么时候用抽象类?抽象类和接口存在的意义是什么?能解决哪些编程问题?”等等。你可以先试着回答一下,刚刚我提出的几个问题。如果你对某些问题还有些模糊不清,那也没关系,今天,我会带你把这几个问题彻底搞清楚。下面我们就一起来看什么是抽象类和接口?区别在哪里?不同的编程语言对接口和抽象类的定义方式可能有些差别,但差别并不会很大。Java这种编程语言,既支持抽象类,也支持接口,所以,为了让你对这两个语法概念有比较直观的认识,我们拿Java这种编程语言来举例讲解。首先,我们来看一下,在Java这种编程语言中,我们是如何定义抽象类的。下面这段代码是一个比较典型的抽象类的使用场景(模板设计模式) 。Logger是一个记录日志的抽象类, FileLogger和MessageQueueLogger继承Logger,分别实现两种不同的日志记录方式:记录日志到文件中和记录日志到消息队列中。FileLogger和MessageQueueLogger两个子类复用了父类Logger中的name,enabled,minPermittedLevel属性和log()方法,但因为这两个子类写日志的方式不同它们又各自重写了父类中的doLog()方法。// 抽象类 public abstract class Logger {prívate String name;private boolean enabled;private Level minPermittedLevel;public Logger(String name, boolean enabled, Level minPermittedLevel) {this.name name;this.enabled enabled;this.minPermittedLevel minPermittedLevel;}public void log(Level level, String message) {boolean loggable enabled (minPermittedLevel.intValue() level.intValue());if (!loggable) return;doLog(level, message);}protected abstract void doLog(Level level, String message); } //抽象类的子类:输出日志到文件 public class FileLogger extends Logger {private Writer filewriter;public FileLogger(String name, boolean enabled,Level minPermittedLevel, String filepath) {super(name, enabled, minPermittedLevel);this.filewriter new Filewriter(filepath);}overridepublic void doLog(Level level, String mesage) {//格式化level和message,输出到日志文件filewriter.write(...);} } //抽象类的子类:输出日志到消息中间件(比如kafka) public class MessageQueueLogger extends Logger{private MessageQueueClient msgQueueClient;public MessageQueueLogger(String name, boolean enabled,Level minPermittedLevel, MessageQueueClient msgQueueClient) {super(name, enabled, minPermittedLevel);this.msgQueueClient msgQueueClient;}overrideprotected void doLog(Level level, String mesage) {// 格式化level和message输出到消息中间件msgQueueClient.send(...);} }通过上面的这个例子,我们来看一下,抽象类具有哪些特性。我总结了下面三点。抽象类不允许被实例化,只能被继承。也就是说,你不能new一个抽象类的对象出来(Logger logger new Logger(.);会报编译错误。抽象类可以包含属性和方法。方法既可以包含代码实现(比如Logger中的log0方法) ,也可以不包含代码实现(比如Logger中的doLog0方法) 。不包含代码实现的方法叫作抽象方法。子类继承抽象类,必须实现抽象类中的所有抽象方法。对应到例子代码中就是,所有继承Logger抽象类的子类,都必须重写doLog0方法。刚刚我们讲了如何定义抽象类,现在我们再来看一下,在Java这种编程语言中,我们如何定义接口。// 接口 publíc interface Filter {void doFilter(RpcRequest req) throws RpcException; // 接口实现类鉴权过滤器 public class AuthencationFilter implements Filter {overridepublic void doFilter(RpcRequest reg) throws RpcException {//...鉴权逻辑..} } // 接口实现类:限流过滤器 public class RateLimitFilter implements Filter{Overridepublic void doFilter(RpcRequest req) throws RpcException{//...限流逻辑...} } //过滤器使用Demo public class Application {// filters.add(new AuthencationFilter());// filters.add(new RateLimitFilter());private List filters new ArrayList();public void handleRpcRequest(RpcRequest req){try {for (Filter filter : filters) {filter.doFilter(req);}} catch (RpcException e) {// ...处理过滤结果...}// ...省略其他处理逻辑...} }上面这段代码是一个比较典型的接口的使用场景。我们通过Java中的interface关键字定义了一个Filter接口。AuthencationFilter和RateLimitFilter是接口的两个实现类,分别实现了对RPC请求鉴权和限流的过滤功能。代码非常简洁。结合代码,我们再来看一下,接口都有哪些特性。我也总结了三点。接口不能包含属性(也就是成员变量)。接口只能声明方法,方法不能包含代码实现。类实现接口的时候,必须实现接口中声明的所有方法。前面我们讲了抽象类和接口的定义,以及各自的语法特性。从语法特性上对比,这两者有比较大的区别,比如抽象类中可以定义属性、才法的实现,而接口中不能定义属性,方法也不能包含代码实现等等。除了语法特性,从设计的角度,两者也有比较大的区别。抽象类实际上就是类只不过是一种特殊的类这种类不能被实例化为对象只能被子类继承。我们知道继承关系是一种is-a的关系那抽象类既然属于类也表示一种is-a的关系。相对于抽象类的is-a关系来说接口表示一种has-a关系表示具有某些功能。对于接口有一个更加形象的叫法那就是协议(contract) 。抽象类和接口能解决什么编程问题刚刚我们学习了抽象类和接口的定义和区别,现在我们再来学习一下抽象类和接口存在的意义,让你知其然知其所以然。首先我们来看一下我什么能要得我它能够解决什么编程问题刚刚我们讲到,抽象类不能实例化,只能被继承。而前面的章节中,我们还讲到,继承能解决代码复用的问题。所以,抽象类也是为代码复用而生的。多个子类可以继承抽象类中定义的属性和方法避免在子类中重复编写相同的代码。不过既然继承本身就能达到代码复用的目的而继承也并不要求父类一定是抽象类那我们不使用抽象类照样也可以实现继承和复用。从这个角度上来讲我们貌似并不需要抽象类这种语法呀。那抽象类除了解决代码复用的问题,还有什么其他存在的意义吗?我们还是拿之前那个打印日志的例子来讲解。我们先对上面的代码做下改造。在改造之后的代码中,Logger不再是抽象类,只是一个普通的父类,删除了Logger中log0), doLog0方法,新增了isLoggable0)方法。FileLogger和MessageQueueLogger还是继承Logger父类,以达到代码复用的目的。具体的代码如下// 父类非抽象类就是普通的类.删除了log(),doLog()新增了isLoggable(). public class Logger {private String name;private boolean enabled;private Level minPermittedLevel;public Logger(String name, boolean enabled, Level minPermittedLevel){//...构造函数不变代码省略...}protected boolean isLoggable() {boolean loggable enabled (minPermittedLevel.intValue() level.intValue());return loggable;} // 子类输出日志到文件 public class FileLogger extends Logger {private writer filewriter;public FileLogger(String name, boolean enabled,Level minPermittedLevel, String filepath)     {//…..构造函数不变,代码省略...}public void log(Level level, String mesage){if (!isLoggable()) return;//格式化level和message,输出到日志文件filewriter.write(...);} 子类输出日志到消息中间件比如kafka) public class MessageQueueLogger extends Logger { private MessageQueueClient msgQueueClient; public MessageQueueLogger(String name, boolean enabled, Level minPermittedLevel, MessageQueueClient msgQueueClient){ //...构造函数不变代码省略... } public void log(Level level, String mesage) { if (!isLoggable()) return; // 格式化level和message,输出到消息中间件 msgQueueClient.send(...); }这个设计思路虽然达到了代码复用的目的,但是无法使用多态特性了。像下面这样编写代码,就会出现编译错误,因为Logger中并没有定义log0方法。这个设计思路虽然达到了代码复用的目的,但是无法使用多态特性了。像下面这样编写代码,就会出现编译错误,因为Logger中并没有定义log0方法。Logger logger new FileLogger(access-log, true, Level.WARN, /users/users/access.log); logger.log(Level.ERROR, This is a test log message.);你可能会说,这个问题解决起来很简单啊。我们在Logger父类中,定义一个空的log0方法,让子类重写父类的log()方法,实现自己的记录日志的逻辑不就可以了吗public class Logger {//...省略部分代码...public void log(Level level, String mesage) { // do nothing... }public class FileLogger extends Logger {//...省略部分代码...Overridepublic void log(Level level, String mesage){if (lisLoggable()) return;// 格式化level和message,输出到日志文件filewriter.write(...);} } public class MessageQueueLogger extends Logger{// ...省略部分代码...Overridepublic void log(Level level, String mesage) {if (!isLoggable()) return;// 格式化level和message,输出到消息中间件msgQueueClient.send(...);} }这个设计思路能用,但是,它显然没有之前通过抽象类的实现思路优雅。我为什么这么说呢?主要有以下几点原因。在Logger中定义一个空的方法,会影响代码的可读性。如果我们不熟悉Logger背后的设计思想,代码注释又不怎么给力,我们在阅读Logger代码的时候,就可能对为什么定义一个空的log0方法而感到疑惑,需要查看Logger、 FileLogger,MessageQueueLogger之间的继承关系,才能弄明白其设计意图。当创建一个新的子类继承Logger父类的时候,我们有可能会忘记重新实现log0方法。之前基于抽象类的设计思路,编译器会强制要求子类重写log0方法,否则会报编译错误。你可能会说,我既然要定义一个新的Logger子类,怎么会忘记重新实现log0方法呢?我们举的例子比较简单, Logger中的方法不多,代码行数也很少。但是,如果Logger有几百行,有n多方法,除非你对Logger的设计非常熟悉,否则忘记重新实现log0方法,也不是不可能的。Logger可以被实例化换句话说我们可以new一个Logger出来并且调用空的log0方法。这也增加了类被误用的风险。当然,这个问题可以通过设置私有的构造函数的方式来解决。不过,显然没有通过抽象类来的优雅。其次我们再来看一下我们为什么需要接口它能够解决什么编程问题抽象类更多的是为了代码复用而接口就更侧重于解耦。接口是对行为的一种抽象相当于一组协议或者契约你可以联想类比一下API接口。调用者只需要关注抽象的接口,不需要了解具体的实现,具体的实现代码对调用者透明。接口实现了约定和实现相分离,可以降低代码间的耦合性,提高代码的可扩展性。实际上,接口是一个比抽象类应用更加广泛、更加重要的知识点。比如,我们经常提到的“基于接口而非实现编程”,就是一条几乎天天会用到,并且能极大地提高代码的灵活性、扩展性的设计思想。关于接口这个知识点,我会单独再用一节课的时间,更加详细全面的讲解,这里就不展开了。如何模拟抽象类和接口两个语法概念在前面举的例子中,我们使用Java的接口语法实现了一个Filter过滤器。不过,如果你熟悉的是C这种编程语言,你可能会说, C只有抽象类并没有接口那从代码实现的角度上来说是不是就无法实现Filter的设计思路了呢实际上,我们可以通过抽象类来模拟接口。怎么来模拟呢?这是一个不错的面试题,你可以先思考一下,然后再来看我的讲解。我们先来回忆一下接口的定义:接口中没有成员变量,只有方法声明,没有方法实现,实现接口的类必须实现接口中的所有方法。只要满足这样几点,从设计的角度上来说,我们就可以把它叫作接口。实际上,要满足接口的这些语法特性并不难。在下面这段C代码中,我们就用抽象类模拟了一个接口(下面这段代码实际上是策略模式中的一段代码)。class Strategy { // 用抽象类模拟接口public: ~Strategy(); virtual void algorithm()0;protected: Strategy(); };抽象类Strategy没有定义任何属性,并且所有的方法都声明为virtual类型(等同于Java中的abstract关键字) ,这样,所有的方法都不能有代码实现并且所有继承这个抽象类的子类都要实现这些方法。从语法特性上来看这个抽象类就相当于一个接口。不过,如果你熟悉的既不是Java,也不是C,而是现在比较流行的动态编程语言,比如Python, Ruby等,你可能还会有疑问:在这些动态语言中,不仅没有接口的概念,也没有类似abstract, virtual这样的关键字来定义抽象类,那该如何实现上面的讲到的Filter, Logger的设计思路呢?实际上,除了用抽象类来模拟接口之外,我们还可以用普通类来模拟接口。具体的Java代码实现如下所示。public class MockInteface {protected MockInteface() {}public void funcA() {throw new MethodUnSupportedException();} }我们知道类中的方法必须包含实现这个不符合接口的定义。但是我们可以让类中的方法抛出MethodUnSupportedException异常来模拟不包含实现的接口,并且能强迫子类在继承这个父类的时候,都去主动实现父类的方法,否则就会在运行时抛出异常。我们将构造函数设置成protected属性的,这样就能避免非同包下的类去实例化Mockinterface。不过,这样还是无法避免同包中的类去实例化Mockinterface。为了解决这个问题,我们可以学习Google Guava中VisibleForTesting注解的做法,自定义一个注解,人为表明不可实例化。刚刚我们讲了如何用抽象类来模拟接口,以及如何用普通类来模拟接口,那如何用普通类来模拟抽象类呢?这个问题留给你自己思考,你可以留言说说你的实现方法。实际上对于动态编程语言来说还有一种对接口支持的策略那就是duck-typing。我们在上一节课中讲到多态的时候也有讲过你可以再回忆一下。如何决定该用抽象类还是接口?刚刚的讲解可能有些偏理论,现在,我们就从真实项目开发的角度来看一下,在代码设计、编程开发的时候,什么时候该用抽象类?什么时候该用接口?实际上判断的标准很简单。如果我们要表示一种is-a的关系并且是为了解决代码复用的问题我们就用抽象类如果我们要表示_x0008_一种has-a关系并且是为了解决抽象而非代码复用的问题那我们就可以使用接口。从类的继承层次上来看,抽象类是一种自下而上的设计思路,先有子类的代码重复,然后再抽象成上层的父类(也就是抽象类) 。而接口正好相反它是一种自上而下的设计思路。我们在编程的时候一般都是先设计接口再去考虑具体的实现。重点回顾好了,今天内容就讲完了我们一块来总结回顾一下,你需要掌握的重点内容。1.抽象类和接口的语法特性抽象类不允许被实例化,只能被继承。它可以包含属性和方法。方法既可以包含代码实现,也可以不包含代码实现。不包含代码实现的方法叫作抽象方法。子类继承抽象类必须实现抽象类中的所有抽象方法。接口不能包含属性只能声明方法方法不能包含代码实现。类实现接口的时候,必须实现接口中声明的所有方法。2.抽象类和接口存在的意义抽象类是对成员变量和方法的抽象是一种is-a关系是为了解决代码复用问题。接口仅仅是对方法的抽象是一种has-a关系表示具有某一组行为特性,是为了解决解耦问题,隔离接口和具体的实现,提高代码的扩展性。3.抽象类和接口的应用场景区别什么时候该用抽象类什么时候该用接口实际上判断的标准很简单。如果要表示一种is-a的关系并且是为了解决代码复用问题我们就用抽象类如果要表示_x0008_一种has-a关系并且是为了解决抽象而非代码复用问题那我们就用接口。课堂讨论1.你熟悉的编程语言是否有现成的语法支持接口和抽象类呢具体是如何定义的呢2.前面我们提到,接口和抽象类是两个经常在面试中被问到的概念。学习完今天的内容之后,你是否对抽象类和接口有一个新的认识呢如果面试官再让你聊聊接口和抽象类你会如何回答呢
http://www.hkea.cn/news/14449487/

相关文章:

  • 网站h1如何自己建设一个网站
  • 网站建设结课策划书网址的英文
  • 传奇网站模板使用石家庄做家教网站
  • 常见的网站建设技术网站文件夹没有权限
  • 网站外链价格网站长期建设 运营计划
  • 无锡网站的优化哪家好电商网站开发分销商
  • 世界网站北京网站优化关键词排名
  • ftp服务器搭建设置网站信息河北网站制作公司报价
  • 山东建设管理局网站创什么网站吸引人
  • 湘潭企业网站建设 磐石网络门户网站 建设 北京 航天
  • 提升访问境外网站速度wordpress写模版
  • 做网站前期工作果洛营销网站建设公司
  • 深圳最专业的高端网站建设如何弄微信小程序店铺
  • 公司网站域名备案wordpress推广机制
  • 做seo网站 公司周口logo设计公司
  • 个人怎么建网站网站建设开发合同书(终极版)
  • 唯品会一家做特卖的网站 分析如何建一个购物网站
  • 安全培训网站如何做网站不容易被攻击
  • 做企业门户网站要准备哪些内容app 门户网站
  • 淘宝优惠网站建设宁波外贸公司一览表
  • 建设摩托车官网官方网站wordpress怎么加背景
  • 建网站的意义在试用网站做推广
  • 厦门的网站建设公司哪家好网站建设的报价为什么不同
  • linux系统网站架构做自行车网站应该注意什么
  • 贵阳58同城做网站公司有哪些个人网站备案所需材料
  • 烟台城乡建设学校96级给排水网站佛山广告设计公司排名
  • 网站 云建站中国互联网数据平台
  • 包装设计网站哪个好用外贸公司一年能赚多少
  • 如何在网上做网站中医药文化建设网站
  • 自建购物网站网站图片素材下载