石油网站编辑怎么做苏州知名网站建设设计
- 作者: 五速梦信息网
- 时间: 2026年03月21日 08:45
当前位置: 首页 > news >正文
石油网站编辑怎么做,苏州知名网站建设设计,手机购买网站源码,wordpress页码颜色变更目录 1.引言 2.抽象类和接口的定义与区别 3.抽象类和接口存在的意义 4.模拟实现抽象类和接口 5.抽象类和接口的应用场景 1.引言 在面向对象编程中#xff0c;抽象类和接口是两个经常被提及的语法概念#xff0c;也是面向对象编程的四大特性#xff0c;以及很多设计模式…目录 1.引言 2.抽象类和接口的定义与区别 3.抽象类和接口存在的意义 4.模拟实现抽象类和接口 5.抽象类和接口的应用场景 1.引言 在面向对象编程中抽象类和接口是两个经常被提及的语法概念也是面向对象编程的四大特性以及很多设计模式和设计原则编程实现的基础。例如我们可以使用接口实现面向对象的抽象特性、多态特性和基于接口而非实现的设计原则使用抽象类实现面向对象的继承特性和模板设计模式等等。 不过并不是所有的面向对象编程语言都支持这两个语法概念如C这种编程语言只支持抽象类不支持接口;而像 Python 这样的动态编程语言既不支持抽象类又不支持接口。尽管有些编程语言没有提供现成的语法来支持接口和抽象类但是我们仍然可以通过一些手段模拟实现这两个语法概念。 这两个语法概念不但在工作中经常会被用到而且在面试中经常被提及。接口和抽象类的区别是什么?什么时候使用接口?什么时候使用抽象类?抽象类和接口存在的意义是什么?通过阅读本节内容相信读者可以从中找到答案。 2.抽象类和接口的定义与区别 不同的编程语言对接口和抽象类的定义方式可能有差别但差别并不会很大。因为Java既支持抽象类又支持接口所以我们使用Java进行举例讲解以便读者对这两个有直观的认识。 首先我们看一下如何在 Java 中定义抽象类。 下面这段代码是一个典型的抽象类使用场景(模板设计模式)。Logger 是一个记录日志抽象类FileLogger 类和 MessageQueueLogger 类继承 Logger 类分别实现不同的日志记式:将日志输出到文件中和将日志输出到消息队列中。FileLogger和MessageQueueLogger 两个子类复用了父类 Logger 中的 name、enabled、minPermittedLevel 属性以及log()方法,因为这两个子类输出日志的方式不同所以它们又各自重写了父类中的 doLog()方法。 public abstract class Logger{private String name;private boolean enabled;private evel 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.intValve());if(!loggable) return;doLog(levelmessage);}protected abstract void doLog (Level level,String message); }//抽象类的子类:输出日志到文件 public class FileLogger extends Logger{private Writer fileWriter;public FileLogger(String name,boolean enabled.Ievel minPermittedLevel,String filepath){super(name,enabled,minPermittedLevel);this.fileWriter new FileWriter(filepath);}0verridepublic void doLog(Level level,string mesage){//格式化leve1和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){//格式化1evel和message并输出到消息中间件msgQueueClient.send(…);} } 结合上述示例我们总结了下列抽象类的特点: 1)抽象类不允许被实例化只能被继承。也就是说我们不能通过关键字 new定义一个 抽象类的对象(编写“Logger loggernew Logger(..);”语句会报编译错误)。 2)抽象类可以包含属性和方法。方法可以包含代码实现(如Logger类中的log()方法)也可以不包含代码实现(如Logger 类中的 doLog()方法)。不包含代码实现的方法称为抽象方法。 3)子类继承抽象类时必须实现抽象类中的所有抽象方法。对应到示例代码中所有继承Logger 抽象类的子类都必须重写 doLog()方法。 上面是对抽象类的定义。接下来我们看一下如何在Java 中定义接口。我们还是先看一段示例代码。 public interface Filter {void doFilter(RpcRequest req)throws RpcException; }//接口实现类:鉴权过滤器 public class AuthencationFilter implements Filter {Overridepublic void doFilter(RpcRequest req)throws RpcException {//省略鉴权逻辑…} }//接口实现类:限流过滤器 public class RatelimitFilter implements Filter {Overridepublic void doFilter(RpcRequest req) throws RpcException {//…省略限流逻辑} }//过滤器使用示例 public class Application {private listFilter filters new ArrayList();public Application(){filters.add(new AuthencationFilter());filters.add(new RatelimitFilter());public void handleRpcRequest(RpcRequest req){try{for(Filter filter : filters ){filter.doFilter(req);}}catch(RpcException e){//..省略处理过滤结果.}}//..省略其他处理逻辑.} } 上述代码是一个典型的接口使用场景。通过Java 中的 interface 关键字我们定义了一个Filter 接口。AuthencationFilter 和RateLimitFiliter是接口的两个实现类分别实现了对RPC求鉴权和限流。结合上述代码我们总结了下列接口的特点: 1)接口不能包含属性(也就是成员变量)。 2)接口只能声明方法方法不能包含代码实现。 3)类实现接口时必须实现接口中声明的所有方法。 有些读者可能说在Java 1.8版本之后接口中的方法可以包含代码实现并且接口可以包含静态成员变量。注意这只不过是Java语言对接口定义的妥协目的是方便使用。抛开Java 这一具体的编程语言接口仍然具有上述3个特点。 在上文中我们介绍了抽象类和接口的定义以及各自的语法特性。从语法特性方面对比抽象类和接口有较大的区别如抽象类中可以定义属性、方法的实现而接口中不能定义属性方法也不能包含代码实现等等。除语法特性以外从设计的角度对比二者也有较大的区别。 抽象类也属于类只不过是一种特殊的类这种类不能被实例化为对象只能被子类继承。我们知道继承关系是一种is-a关系那么抽象类既然属于类也表示一种is-a关系。相比抽象类的is-a关系接口表示一种has-a关系(或can-do关系、behave like 关系)表示具有某些功能。因此接口有一个形象的叫法:协议(contract)。 3.抽象类和接口存在的意义 在上面我们介绍了抽象类和接口的定义与区别现在我们探讨一下抽象类和接口存在的意义以便读者知其然知其所以然。 为什么需要抽象类?它能够在编程中解决什么问题?在上面我们讲到抽象类不能被实例化只能被继承。之前我们还讲过继承能够解决代码复用问题。因此抽象类是为代码复用而生的。多个子类可以继承抽象类中定义的属性和方法这样可以避免在子类中重复编写相同的代码。 既然继承就能达到代码复用的目的而维承并不要求父类必须是抽象类那么不使用抽象类照样可以实现继承和复用。从这个角度来看抽象类语法似乎是多余的。那么除解决代码复用问题以外抽象类还有其他存在的意义吗? 我们还是结合之前打印日志的示例代码进行讲解。不过我们需要先对之前的代码进行改造。在改造之后Logger不再是独象类。万法一个普通类。另外我们删除了Logger类中的log()、doLog()方法新增了isLoggable()方法,FileLogger类和 MessageQueueLogger 类仍级继承 Logger 类。具体代码如下 //父类Logger, 非抽象类就是普通类删除了log()和doLog()方法新增了 isLoggeable()方法 public abstract class Logger{private String name;private boolean enabled;private evel minPermittedLevel;public Logger(String name, boolean enabled, Level minPermittedLevel){this.name name;this.enabled enabled;this.minPermittedLevel minPermittedLevel;}protected boolean isLoggable(){boolean loggable enabled (minPermittedLevel.intValue()level.intValve());return loggable;} }//抽象类的子类:输出日志到文件 public class FileLogger extends Logger{private Writer fileWriter;public FileLogger(String name,boolean enabled.Ievel minPermittedLevel,String filepath){super(name,enabled,minPermittedLevel);this.fileWriter new FileWriter(filepath);}0verridepublic void log(Level level,string mesage){if (!isLoggable())return;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;}Overridepublic void log(Level level,string mesage){if (!isLoggable())return;msgQueueClient.send(…);} } 虽然上面这段代码的设计思路达到了代码复用的目的但是无法使用多态特性。如果我们像下面这样编写代码就会出现编译错误因为Logger类中并没有定义log()方法。 Logger logger new FileLogger(access-log,true, Level.WARN, /users/wangzheng/access.log) ; logger.log(Level,ERROR, This is a test log message .); 读者可能会说这个问题的解决很简单在Logger类中定义一个空的log()方法让子类重写 Logger类的log()方法并实现自己的日志输出逻辑不就可以了吗?代码如下所示。 Public class Logger{//…省略部分代码…Public void log(Level levelstring mesage){ //方法体为空} }public class FileLogger extends Logger{//..省略部分代码..Overridepublic void log(Level level,String mesage){if(!isLoggable())return;//格式化1evel和message并输出到日志文件filewriter.write(…);} }public class MessageQueuelogger extends Logger{//..省略部分代码..Overridepublic void log(Level level, string mesage){if(!isLoggable())return;//格式化1evel和message并输出到消息中间件msgQueueClient.send(…);} } 虽然上面这段代码的设计思路可用能够解决问题但是它显然没有之前基于抽象*。设计思路优雅理由如下。 1)在Logger类中定义一个空的方法会影响代码的可读性。如果我们不熟悉Logger类背后的设计思想加之代码的注释不详细那么在阅读Logger类的代码时有可解生为什么定义一个空的log()方法的疑问。或许我们需要通过查看Logger、FileLogger和MessageQueueLogger 之间的继承关系才能明白其背后的设计意图。 2)当创建一个新的子类并继承Logger类时我们很有可能忘记重新实现log()方法。前基于抽象类的设计思路编译器会强制要求子类重写log()方法否则会报编译错误。读者可能会问既然要定义一个新的Logger 类的子类那么怎么会忘记重新实现 log()方法呢?其实我们举的例子比较简单Logger类中的方法不多代码行数也很少。我们可以想象一下如果Logger类中有几百行代码包含很多方法除非我们对Logger类的设计非常熟悉否则极有可能忘记重新实现log()方法。 3)Logger类可以被实例化换句话说我们可以通过关键字new定义一个Logger 类的对象并且调用它的空的log()方法。这增加了类被误用的风险。当然这个问题可以通过设置私有的构造函数的方式来解决。不过这显然没有基于抽象类的实现思路优雅。为什么需要接口?它能够在编程中解决什么问题?抽象类侧重代码复用而接口侧重解耦。接口是对行为的一种抽象相当于一组协议或契约读者可以类比API。调用者只需要关注抽象的接口不需要了解具体的实现具体的实对调用者透明。接口实现了约定和实现分离可以降低代码的耦合度提高代码的可扩展性。 4.模拟实现抽象类和接口 有些编程语言只有抽象类并没有接口如C。我们可以通过抽象类模拟接口只要它满足接口的特性(接口中没有成员变量只有方法声明没有实现方法实现接口的类必须实现接口中的所有方法)即可。在下面这段C代码中我们使用抽象类模拟了一个接口。 class Strategy{//用抽象类模拟接口public:virtual ~Strategy();virtual void algorithm() 0,protected:Strategy(); } 抽象类 Strategy 没有定义任何属性并且所有的方法都声明为virual(等同于 Java中的abstract 关键字)类型这样所有的方法都不能有代码实现并且所有继承这个抽象类的子类都要实现这些方法。从语法特性上来看这个抽象类就相当于一个接口。 不过现在流行的动态编程语言如Python、Ruby等它们不但没有接口的概念而且没有抽象类。在这种情况下我们可以使用普通类模拟接口。具体的Java代码实现如下。 public class MockInterface{protected MockInterface();public void funcA(){throw new MethodUnSupportedException();} } 我们知道类中的方法必须包含实现但这不符合接口的定义。其实我们可以让类中的方法抛出 MethodUnSupportedException 异常来模拟不包含实现的接口并且在子类继承父类时强迫子类主动实现父类的方法否则会在运行时抛出异常。那么如何避免这个类被实例化呢?我们只需要将构造函数设置成protected属性这样就能避免非同一包(package)下的类去实例化 MockInterface。不过这样做还是无法避免同一包下的类去实例化 MockInterface.为了解决这个问题我们可以学习Google Guava中 VisibleForTesting注解的做法自定义个注解人为地表明其不可实例化。 上面讲了如何用抽象类来模拟接口以及如何用普通类来模拟接口那么如何用普通类来模拟抽象类呢?我们可以类比 MockInterface 类的处理方式让本该为abstract的方法内部抛出MethodUnSupportedException异常并且将构造函数设置为protected 属性避免实例化。 5.抽象类和接口的应用场景 在真实的项目开发中什么时候该用抽象类?什么时候该用接口?实际上判断的标准很简单。如果我们要表示一种is-a关系并且是为了解决代码复用的问题那么使用抽象类;如果我们要表示一种 has-a关系并且是为了解决抽象而非代码复用的问题那么使用接口。 从类的继承层次上来看抽象类是一种自下而上的设计思路先有子类的代码重复再抽象出上层的父类(也就是抽象类)。而接口正好相反它是一种自上而下的设计思路。在编程开发时一般先设计接口再考虑具体的实现。
- 上一篇: 石药网站环保产品企业网站建设
- 下一篇: 时代空间网站php在线做网站
相关文章
-
石药网站环保产品企业网站建设
石药网站环保产品企业网站建设
- 技术栈
- 2026年03月21日
-
石头科技 网站开发wordpress建站教程网
石头科技 网站开发wordpress建站教程网
- 技术栈
- 2026年03月21日
-
石狮做网站网站建设需注意点
石狮做网站网站建设需注意点
- 技术栈
- 2026年03月21日
-
时代空间网站php在线做网站
时代空间网站php在线做网站
- 技术栈
- 2026年03月21日
-
时代强个人网站网店营销策略有哪些
时代强个人网站网店营销策略有哪些
- 技术栈
- 2026年03月21日
-
时代设计网 新网站深圳开公司流程及费用
时代设计网 新网站深圳开公司流程及费用
- 技术栈
- 2026年03月21日
