I have a class PieClass that accepts data $data and iterate this data by following schema:
public function setData($data) {
foreach($data as $value) {
$a[$value->id] = $value;
}
}
So, it expects to get $data by the concrete format.
There is another class model is named as ClassModel. Using dependency injection it takes any model like:
class ClassModel {
public $model;
public function __constructor($model) {
$this->model = $model;
}
public function data(){
return $this->model->query("...")->get();
}
}
So, as getData() get return different set of fields it should be prepared to use in PieClass class.
Therefore I try to create class Adoptor beetwen ClassModel and PieClass.
I have started to create interface:
interface IDataAdapter {
public function data() {}
}
Then I created class:
class GraphPieWorkAdapter implements IDataAdapter {
public function data() {
}
}
Also class ClassModel must implement IDataAdapter:
class ClassModel implements IDataAdapter {
public function data();
}
What to do next, how to utilize adopt pattern?
Related
Suppose I have the following :
<?php
class Final extends Intermediate {
public function final_level() {
$this->low_level();
$this->inter_level();
}
}
class Intermediate extends Lib1 {
public function inter_level() {
$this->low_level();
}
}
class Lib1 {
public function low_level1();
public function low_level2();
}
class Lib2 {
public function low_level1();
public function low_level2();
}
I would like to change the Intermediate class to extend Lib1 or Lib2, depending on some conditions, without duplicating Intermediate and Final code content.
All low_level functions are the same for both Lib.
In the end, I would like to have a Final1 class that use Lib1 (and Final2 that use Lib2).
How could I achieve this ?
You cannot achieve this via inheritance but you can via delegation
With this approach you delegate the implementation of some methods to a 'delegate' object rather than a base class.
Here it is an example:
<?php
class Final extends Intermediate {
public function __construct(Lib delegate) {
parent::__construct(delegate);
}
public function final_level() {
$this->low_level();
$this->inter_level();
}
}
class Intermediate implements Lib { //here you implement an interface rather than extending a class
private Lib delegate;
public function __construct(Lib delegate) {
$this->delegate = delegate;
}
public function inter_level() {
$this->low_level();
}
public function low_level() {
//delegate!
$this->delegate->low_level();
}
}
class Lib1 implements Lib{
public function low_level(); //implementation #1
}
class Lib2 implements Lib {
public function low_level(); //implementation #2
}
interface Lib {
public function low_level();
}
now you can create your final1 and final2 object in this way:
$final1 = new Final(new Lib1());
$final2 = new Final(new Lib2());
or, if you prefer, you can create the Final1 and Final2 classes extending from Final:
class Final1 extends Final {
public function __construct()
{
parent::__construct(new Lib1());
}
}
class Final2 extends Final {
public function __construct()
{
parent::__construct(new Lib2());
}
}
$final1 = new Final1();
$final2 = new Final2();
Say I have the following code, is there a way to somehow extend an abstract class on a child and require a different type of argument in the "overloaded" function. I want to insert various types of objects in the Collection through the add function. In some cases, I'd like to insert an Error object, sometimes some other (XYZ) object, and let's say that all those objects extend the same abstract class called Parent.
I would appreciate if somebody could tell me if something like this is even possible, and if it is suggest some ways to accomplish this. Note that production server on which I intend to host the application runs on php 5.6.40.
Thank you in advance.
namespace App;
use App\Models\Parent;
abstract class Collection
{
protected $collection;
public function __construct()
{
$this->collection = array();
}
abstract public function add($key, Parent $item);
}
public class ErrorList extends Collection
{
public function __construct()
{
parent::__construct();
}
public function add($key, Error $item)
{
$this->collection[$key] = $item;
}
}
namespace App\Models;
abstract class Parent {}
public class Error extends Parent {}
public class XYZ extends Parent{}
Try this
abstract class Collection
{
protected $collection;
public function __construct()
{
$this->collection = array();
}
//no type hinting
abstract public function add($key, $item);
}
class ErrorList extends Collection
{
// this constructor doing nothing , it can be removed and
// parent constructor will still be called unlike java or any other
// OOP
public function __construct()
{
parent::__construct();
}
//no type hinting
public function add($key, $item)
{
//code
}
}
If you're extending a class or implementing an interface the signature must match. You can however implement type checking yourself and type hint in a docblock.
As a side note, public class is invalid syntax.
abstract class Collection
{
protected $collection;
public function __construct()
{
$this->collection = array();
}
abstract public function add($key, Parent $item);
}
class ErrorList extends Collection
{
public function __construct()
{
parent::__construct();
}
/**
* #param $key
* #param Parent|Error $item
*/
public function add($key, Parent $item)
{
if (!($item instanceof Error)) {
throw new \InvalidArgumentException('Unable to add object to error list: ' . get_class($item));
}
$this->collection[$key] = $item;
}
}
I have an abstract class, in which I want to call method, from a class that is declared in the child (extending) class. An example looks like this:
The abstract class:
abstract class NumberGenerator
{
protected function generate($input){
return MyClass::MyMethod($input);
}
}
My child/extending class:
use TomsFolder\MyClass;
use MyFolder\NumberGenerator;
class TomsNumberGenerator extends NumberGenerator
{
public function generate(string $applicantId): string
{
return $this->generate();
}
}
Another child/extending class:
use DavesFolder\MyClass;
use MyFolder\NumberGenerator;
class DavesNumberGenerator extends NumberGenerator
{
public function generate(string $applicantId): string
{
return $this->generate();
}
}
So I want to call MyClass::MyMethod in NumberGenerator. However it is only imported in TomsNumberGenerator.
The reason I want to do it like is because, I have classes like DavesNumberGenerator which calls a different MyClass.
When I try this, I get 'MyClass is not found in NumberGenerator'. Is there any way to make this work?
Try putting the namespace use statement before the actual class:
NumberGenerator.php
use MyFolder\MyClass;
abstract class NumberGenerator
{
protected function generate($input){
return MyClass::MyMethod($input);
}
}
EDIT
Try this:
NumberGenerator.php
abstract class NumberGenerator
{
protected function generate($class_name, $input){
return call_user_func($class_name . '::MyMethod', $input);
}
}
TomsNumberGenerator.php
use TomsFolder\MyClass;
use MyFolder\NumberGenerator;
class TomsNumberGenerator extends NumberGenerator
{
public function generate(string $applicantId): string
{
return $this->generate(get_class(new MyClass()), $applicantId);
}
}
You have to use interface for this.
You can do the following
Create MyClassInterface
interface MyClassInterface {
public function MyMethod();
}
Implement this interface in some classes
class MyClass1 implements MyClassInterface {
public function MyMethod() {
// implementation
}
}
class MyClass2 implements MyClassInterface {
public function MyMethod() {
// implementation 2
}
}
Add abstract method to NumberGenerator
abstract class NumberGenerator {
abstract protected function GetMyClass(): MyClassInterface;
protected function generate($input){
return $this->GetMyClass()->MyMethod($input);
}
}
Implement GetMyClass function inside child classes
class TomsNumberGenerator extends NumberGenerator
{
protected function GetMyClass(): MyClassInterface {
return new MyClass1();
}
}
class DavesNumberGenerator extends NumberGenerator
{
protected function GetMyClass(): MyClassInterface {
return new MyClass2();
}
}
PS If you want to use static, you can change abstract inside NumberGenerator class, to change string. In this case, your generate will look like this:
protected function generate($input){
return call_user_func($this->GetMyClass() . '::MyMethod', [$input]);
}
I'm having some confusion with the adapter pattern and am wondering if it is the right tool for what I'm trying to accomplish.
Basically, I'm trying to get a class written by another developer to conform to an interface that I've written while also retaining the other methods from that class.
So I've written the following interface for a container object:
interface MyContainerInterface
{
public function has($key);
public function get($key);
public function add($key, $value);
public function remove($key);
}
I've also written an adapter that implements that interface:
class OtherContainerAdapter implements MyContainerInterface
{
protected $container;
public function __construct(ContainerInteface $container) {
$this->container = $container;
}
public function has($key) {
$this->container->isRegistered($key);
}
...
}
And am using it in my class as follows:
class MyClass implements \ArrayAccess
{
protected $container;
public function __construct(MyContainerInterface $container) {
$this->setContainer($container);
}
public function offsetExists($key) {
$this->container->has($key);
}
...
}
Then my application uses the class as so:
$myClass = new MyClass(new OtherContainerAdapter(new OtherContainer));
The issue I'm having is that in order to use the methods from the adapter I have to write the following:
$myClass->getContainer()->getContainer()->has('some_key');
When ideally it would just be:
$myClass->getContainer()->has('some_key');
$myClass->getContainer()
should return an instance of MyContainerInterface and that has a has() function. It shouldn't have a getContainer() function.
I don't think you need the Adapter Pattern for this. It looks to me like you're after a polymorphic solution, which can be accomplished by simply using an abstract class. No adapter needed.
The interface
interface MyContainerInterface
{
public function has($key);
public function get($key);
public function add($key, $value);
public function remove($key);
}
Then the abstract base class:
class MyContainerBaseClass implements MyContainerInterface, \ArrayAccess
{
public function offsetExists($key) {
$this->has($key);
}
...
}
Then, the sub-class from the other developer:
class ClassByOtherDeveloper extends MyContainerBaseClass
{
public function has($key) {
$this->isRegistered($key);
}
//you also need to implement get(), add(), and remove() since they are still abstract.
...
}
You can use it in your application like this:
$object = new ClassByOtherDeveloper();
$x = $object->has('some_key');
I'm assuming the isRegistered method lives in the implementation from the other developer.
To make it truly polymorphic you wouldn't hard-code the class name, but you'd use a variable that could come from a config file, database, or a Factory.
For example:
$className = "ClassByOtherDeveloper"; //this could be read from a database or some other dynamic source
$object = new $className();
$x = $object->has('some_key');
Is it ok to put factory() method to the factoried object's class?
class User {
public static function factory($id) {
return new User($id);
}
private function __construct($id) {
}
}
And when consider placing factory() method into separated class?
class User {
public function __construct($id) {
}
}
class UserFactory {
public static function factory($id) {
return new User($id)
}
}
I can't see any benefits of using additional class for factory, but I consider that there are some benefits I don't know about. :)
When to put factory() method into factoried object and when put factory() method to separated class?
The advantage with putting the factory method inside the class itself is protecting the class from being instantiated without using the factory method:
class User {
public static function factory($id) {
return new User($id);
}
private function __construct($id) {
// Now, only the factory method within this class can call this method.
// (Additionally, this method was static, which it shouldn't.)
}
}
I let other add to this with advantages of the opposite solution.
If you have a static creator method there is not much use in putting in into a factory.
It's only really useful to put factory method in it's own class if it isn't static and you want to inject it somewhere.
class User {
public static function __construct($id) {
}
}
class UserFactory {
public function factory($id) {
return new User($id)
}
}
class SomethingUserReleated {
public function __construct(UserFactory $factory) {
$this->userFactory = $factory;
}
public function iNeedToCreateAnUserForSomething() {
$userOne = $this->userFactory->factory(1233);
$userTwo = $this->userFactory->factory(123533);
}
}
Since you can't to the above with static methods.
Moving the factory methods into separate class allows you to separate object-methods and factory-specific methods (that are only needed while creating a new object).
class User {
public static function __construct($id, $name){
// call this directly or via Factory
}
}
class UserFactory {
private static function randomName(){
// return some random name
}
public static function factory($id){
return new User($id, UserFactory::randomName());
}
}