看过了一些trait的介绍,也在框架中看到了。但是感觉trait做的事情,用interface是不是也能做呢?
个人感觉每个trait实现的功能都非常集中,也非常轻量,这个很赞,但是相对的有些class可能要同时用好几个trait,而且假如同时继承了类,实现了接口,并且其中包含覆盖,那理清这个类的关系感觉会很困难,这是我最困惑的地方,当然也可能是我技术还不够。
但是既然出了这个语法,肯定还是有他的道理的,所以就想问一下,项目中使用trait的意义是什么呢?
欢迎选择我的课程,让我们一起见证您的进步~~
有不少目的,我相信其他的答案会从各个角度提及。
我所知道的一个重要目的是:方便代码生成器的工作。
如果一个类的部分代码是生成器产生的,部分代码是自己写的,那么我们肯定希望生成器产生的代码在trait里,我们自己写的代码引用这个trait。这样如果生成器需要重新运行,自写的代码就无需任何变化。
trait
这一点用继承也许也能做到,但PHP没有多继承。同时引用多个生成器产生的代码,只能依赖trait。
这一点你可以看一下 C# 的“部分类”(partial class)。在目的上是很相似的。
trait和interface恰好相反,interface关心的是接口,把实现丢给其他人,而trait完全不关心接口(约定),只提供实现。不那么准确地说的话,trait = abstract class - interface,提供了另一个维度的灵活性
一个常见的应用场景是为接口提供“默认实现”,比如经典的\Psr\Log\LoggerInterface接口,有一堆方法(critical/emerg/info/debug)等等,但实际实现的时候,大家都会把这些方法都转发到log()方法里去,所以PSR提供了\Psr\Log\LoggerTrait,这样既保持了接口的完整(每个错误等级都有独立的方法),又方便了实现者
\Psr\Log\LoggerInterface
log()
\Psr\Log\LoggerTrait
你可以这么理解 1、trait 用来复用代码的2、解决了 php 不能多继承的问题(多继承也会产生问题,这里不展开)3、使用 trait的类,跟 trait 本身是可以没有任何关系的
php
.......
trait 里面定义了实现interface 只是声明这两个还是有区别的
interface
......
PHP和Java等大多数面向对象的语言一样是单继承,既一个类只能继承于一个父类。虽然单继承是公认使代码清晰准确的方式,但有时候多继承也有自己的优势。trait的出现就是一种解决需要多继承场景的方式。多继承的好处就是让一个类继承多个父类的功能,虽然这违反了类单一职责原则,但是在某些场合下,一些小功能使用多继承是最合适不过的。比如Laravel中定义了一个宏trait,只是很简单的让类实现一些类似C宏定义的方法,因为这其中含有一些实体方法和属性,所以通过interface定义是不能实现的,而需要使用这个功能的类又有可能已经继承于其他类,所以通过abstract class定义也是不能实现的,所以这种场合下trait就能体现它的优势了。
PHP
Java
Laravel
C
abstract class
这篇博客中有讲到哦,可以看看http://overtrue.me/articles/2016/04/about-php-trait.html
在解决多继承的代码中用的较多
减少复制粘贴造成的维护不便问题
通俗一点,就是能把重复的方法拆分到一个文件,通过 use 引入以达到代码复用的目的
看了一下trait的定义,并测试了一下。感觉是把设计模式里面的适配器模型做到语言层面了。多继承的语言没用过,不敢做评论。就看到的几个实例,都可以使用适配器+接口实现,只是实现起来比较绕,没有trait这么清晰。
个人理解:在一个类中使用Trait,就相当于这个类也有了Trait中定义的属性和方法。Traits的使用场景是如果多个类都要用到同样的属性或者方法,这个时候使用Traits可以方便的给类增加这些属性或方法,而不用每个类都去继承一个类,如果说继承类是竖向扩展一个类,那么Traits是横向扩展一个类,从而实现代码复用。
Laravel中triat的使用:http://blog.tanteng.me/2015/12/laravel-trait/
有不少目的,我相信其他的答案会从各个角度提及。
我所知道的一个重要目的是:方便代码生成器的工作。
如果一个类的部分代码是生成器产生的,部分代码是自己写的,那么我们肯定希望生成器产生的代码在
trait
里,我们自己写的代码引用这个trait
。这样如果生成器需要重新运行,自写的代码就无需任何变化。这一点用继承也许也能做到,但PHP没有多继承。同时引用多个生成器产生的代码,只能依赖
trait
。这一点你可以看一下 C# 的“部分类”(partial class)。在目的上是很相似的。
trait和interface恰好相反,interface关心的是接口,把实现丢给其他人,而trait完全不关心接口(约定),只提供实现。不那么准确地说的话,trait = abstract class - interface,提供了另一个维度的灵活性
一个常见的应用场景是为接口提供“默认实现”,比如经典的
\Psr\Log\LoggerInterface
接口,有一堆方法(critical/emerg/info/debug)等等,但实际实现的时候,大家都会把这些方法都转发到log()
方法里去,所以PSR提供了\Psr\Log\LoggerTrait
,这样既保持了接口的完整(每个错误等级都有独立的方法),又方便了实现者你可以这么理解
1、
trait
用来复用代码的2、解决了
php
不能多继承的问题(多继承也会产生问题,这里不展开)3、使用
trait
的类,跟trait
本身是可以没有任何关系的.......
trait
里面定义了实现interface
只是声明这两个还是有区别的
......
PHP
和Java
等大多数面向对象的语言一样是单继承,既一个类只能继承于一个父类。虽然单继承是公认使代码清晰准确的方式,但有时候多继承也有自己的优势。trait
的出现就是一种解决需要多继承场景的方式。多继承的好处就是让一个类继承多个父类的功能,虽然这违反了类单一职责原则,但是在某些场合下,一些小功能使用多继承是最合适不过的。比如Laravel
中定义了一个宏trait
,只是很简单的让类实现一些类似C
宏定义的方法,因为这其中含有一些实体方法和属性,所以通过interface
定义是不能实现的,而需要使用这个功能的类又有可能已经继承于其他类,所以通过abstract class
定义也是不能实现的,所以这种场合下trait
就能体现它的优势了。这篇博客中有讲到哦,可以看看
http://overtrue.me/articles/2016/04/about-php-trait.html
在解决多继承的代码中用的较多
减少复制粘贴造成的维护不便问题
通俗一点,就是能把重复的方法拆分到一个文件,通过 use 引入以达到代码复用的目的
看了一下trait的定义,并测试了一下。感觉是把设计模式里面的适配器模型做到语言层面了。
多继承的语言没用过,不敢做评论。就看到的几个实例,都可以使用适配器+接口实现,只是实现起来比较绕,没有trait这么清晰。
个人理解:在一个类中使用Trait,就相当于这个类也有了Trait中定义的属性和方法。Traits的使用场景是如果多个类都要用到同样的属性或者方法,这个时候使用Traits可以方便的给类增加这些属性或方法,而不用每个类都去继承一个类,如果说继承类是竖向扩展一个类,那么Traits是横向扩展一个类,从而实现代码复用。
Laravel中triat的使用:
http://blog.tanteng.me/2015/12/laravel-trait/