NotionCommotion Posted February 12, 2017 Share Posted February 12, 2017 I am new to traits, and am trying to figure out when and how to use them. Please comment on the following. While this is a question about traits, I would welcome (provided advice is also given) any criticism about my use of interfaces should criticism be warranted. Thanks <?php interface CarInterface { public function go(); public function stop(); public function turn(); public function resistRust(); } class Car implements CarInterface { public function go() { //bla bla bla $acceration=$this->accerationRate(); //bla bla bla } public function stop() { //bla bla bla $deacceration=$this->deaccerationRate(); //bla bla bla } public function turn() { //bla bla bla $turnRadius=$this->turnRadius(); //bla bla bla } public function resistRust() { //bla bla bla $resistanceFactor=$this->resistanceFactor(); //bla bla bla } } class Ford extends Car { protected function accerationRate(){/* some script */} protected function deaccerationRate(){/* some script */} protected function turnRadius(){/* some script */} protected function resistanceFactor(){/* some script */} } class Chevrolet extends Car { protected function accerationRate(){/* some script */} protected function deaccerationRate(){/* some script */} protected function turnRadius(){/* some script */} protected function resistanceFactor(){/* some script */} } class FordWithDealerRustProofOption extends Ford { use DealerRustProofOption; } class ChevroletWithDealerRustProofOption extends Ford { use DealerRustProofOption; } trait DealerRustProofOption { protected function resistanceFactor() {/* some script */} } $car=new Ford(); $car=new Chevrolet(); $car=new FordWithDealerRustProofOption(); $car=new ChevroletWithDealerRustProofOption(); Quote Link to comment Share on other sites More sharing options...
Jacques1 Posted February 12, 2017 Share Posted February 12, 2017 (edited) The code is very odd, pretty much from top to bottom. Are you using a good IDE with code analysis? It should show several complaints. Your car interface is fine. However, then you define this strange base class with methods coming out of nowhere. I guess you want the Template method pattern, but then you need to define the template methods (typically they're abstract). Starting out with a generic interface and then immediately setting a very specific base implementation in stone is also odd. The whole point of an interface is to not dictate implementation details. The inner workings of a car are irrelevant; it just has to be able to drive, stop, turn etc. You're free to define a base class for your own cars, but then don't call it “Car”. The cars of somebody else may work entirely different. Traits exist to provide features (mostly public methods, rarely attributes) which can be mixed into existing classes. For example, Ruby has the big Enumerable mixin which adds lots of useful methods to collection-like classes. It's very much like inheritance, except that you can have multiple providers. A trait which only has protected method doesn't make much sense. I think you're again confusing the outer API of a class with its inner workings. Traits are about the API. Edited February 12, 2017 by Jacques1 Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted February 12, 2017 Author Share Posted February 12, 2017 Thanks Jacques1, My need is to learn how to extend more than one class. I go from general to specific, and all is good. Then I need to add some more methods and get stuck. Okay, I maybe see your point about traits should be public methods and not attributes, however, it still seems useful sometimes to have the ability to tweak the resultant object. Regardless, let me concede this point. What if I have both CorvetteStingray extends Corvette extends Chevrolet extends Car and and ShelbyGT350 extends Mustang extends Ford extends Car. The dealer I am talking to offers some cool option where they strap a propeller to the back of any car, and now it can fly! Where can I add the fly() method without giving all cars the ability to fly and without duplicating the fly() method script in multiple classes? Quote Link to comment Share on other sites More sharing options...
requinix Posted February 12, 2017 Share Posted February 12, 2017 The dealer I am talking to offers some cool option where they strap a propeller to the back of any car, and now it can fly! Where can I add the fly() method without giving all cars the ability to fly and without duplicating the fly() method script in multiple classes?You can't. Not with the model you're using. You're talking about something that happens at runtime - unless you want to make a class for every single possible combination of features (spoiler: you don't) then that sort of behavior needs to be managed dynamically. As a first draft, interface ObjectFeature { public function __construct($object); } interface ObjectHasFeatures { public function addFeature($feature); public function getFeature($class); public function hasFeature($class); } trait HasFeatures { private $_hasfeatures_features = []; public function addFeature($class) { $this->_hasfeatures_features[$class] = new $class($this); } public function getFeature($class) { return $this->_hasfeatures_features[$class]; } public function hasFeature($class) { return isset($this->_hasfeatures_features[$class]); } } class Car implements ObjectHasFeatures { use HasFeatures; private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } class FlyingFeature implements ObjectFeature { private $car; public function __construct($object) { assert($object instanceof Car); $this->car = $object; } public function fly() { echo "*{$this->car->getName()} starts flying*\n"; } } $car = new Car("Notion's Car"); $car->addFeature(FlyingFeature::class); $car->getFeature(FlyingFeature::class)->fly(); https://3v4l.org/Qmm0D Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted February 12, 2017 Author Share Posted February 12, 2017 Thanks requinix I've never seen __construct() put in an interface, however, I suppose it makes sense. Include the fly() method as well, right? You are right, I don't wish to make a class for every single possible combination of features, and your approach makes sense. You can't. Not with the model you're using. What was specific about the model I am using which prevents doing so? Are there other models which are commonly used that better support doing so? Quote Link to comment Share on other sites More sharing options...
Jacques1 Posted February 12, 2017 Share Posted February 12, 2017 The Decorator Pattern. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.