Here's what I'm trying to implement in my program:
The program should open a zip file, which contains many data files
The format of the data files can differ between zip files (e.g. csv, tab delimited, or could even be some kind of binary file which needs decoding)
However, within a zip file all data files will be of the same type
I have been reading "Design Patterns" by Gamma et al., and have been looking at the Abstract Factory pattern to try to solve this.
Ideally, I want to have one class for the Zip file, which can read any type of data file within it. I guess I would have two classes - FileTypeA and FileTypeB, which could process different formats of data (although there could be more in the future). I would like a way of telling my ZipFile class which type of file to use when reading the data.
So far, this is what I have come up with:
<?php
/**
* An abstract factory used for creating data files of any type
*/
abstract class DataFileFactory{
abstract function createFile($id);
}
/**
* A factory for creating and setting up a data file of type 'A'
*/
class FileAFactory extends DataFileFactory{
public function createFile($id){
$file = new FileA();
$file->setSampleId($id);
return $file;
}
}
/**
* A factory for creating and setting up a data file of type 'B'
*/
class FileBFactory extends DataFileFactory{
public function createFile($id){
$file = new FileB();
$file->setSampleId($id);
return $file;
}
}
/**
* An abstract class which defines some functionality of a data file
*/
abstract class DataFile{
abstract function readData();
abstract function setSampleId();
}
/**
* Concrete class that processes a data file of type 'A'
*/
class FileA extends DataFile{
public function readData(){
echo "Reading data from a file A<br/>";
}
public function setSampleId(){
echo "Setting sample id of a file A<br/>";
}
}
/**
* Concrete class that processes a data file of type 'B'
*/
class FileB extends DataFile{
public function readData(){
echo "Reading data from a file B<br/>";
}
public function setSampleId(){
echo "Setting sample id of a file B<br/>";
}
}
/**
* Concrete class that reads a zip file and reads each file within the zip
*/
class ZipFile{
private $files = array("file1.txt","file2.txt","file3.txt","file4.txt");//this would be an array read from the zip file
private $sampleId = 1;//this would be derived from some other function
/**
* Read all the files in a zip archive.
* $factory can be an instance of any class that extends DataFileFactory, and is used for creating each file
*/
public function readFiles(DataFileFactory $factory){
foreach($this->files as $fileName){//loop through each file in the zip
$file = $factory->createFile($this->sampleId);//use the factory to create the desired file
$file->readData();//now read the data from the file!
echo "object created of type: ".get_class($file)."<hr/>";
}
}
}
/***********************************************************************************************
* IMPLEMENTATION
***********************************************************************************************/
$zip = new ZipFile();//create a new zip file
$factory = new FileAFactory();//instantiate a new factory, depending on which type of file you want to create
$zip->readFiles($factory);//read the files, passing the correct factory object to it
Can anyone tell me:
(A) Whether this is a good way of achieving what I'm looking for, or is there some simpler way of doing it?
(B) Is this actually the Abstract Factory pattern, or have I completely misunderstood?
Thanks in advance!
It's a good implementation but it can be finetuned a bit if you use interfaces.
An abtract class with all virtual methods it's just a interface so don't use abstract classes, use interfaces.
interface IDataFileFactory{
public function createFile($id);
}
class FileAFactory implements IDataFileFactory
class FileBFactory implements IDataFileFactory
If you find repeating code in FileAFactory and in FileBFactory methods then it is time to refactor your classes and create inheritance.
interface IDataFileFactory{
public function createFile($id);
}
abstract class BaseFileFactory implements IDataFileFactory {
//some methods implementation with common features to avoid repeating code
//some abstract methods to be implemented for A and B FileFactories
//absolute abstract base class has no sense because in php you can use interfaces.
//...
}
class FileAFactory extends BaseFileFactory
class FileBFactory extends BaseFileFactory
Then use throug interface:
public function readFiles(IDataFileFactory $factory){
//create a file using factory
return IDataFile; //return Interface implemented by all DataFile types.
}
You can do the same thing with DataFile base class and so on.
I also recomend to not pass factories in parameters because a factory is out of context. Try to do not mix architecture implementation with data and info process workflow. You can create a container, in a scope accesible for your other classes, to resolve the factory.
The container can, for example, read configuration files to create concrete factory in application bootstrap; read from some value, choosed by the user in previous steps of the user case, stored in a class instance or accepting a parameter in runtime to resolve the factory. It's about implement some kind of simple dependency inyection.
Anyway, this is only my point of view and can be a hurge amount disagreements.
I hope it help.
Related
I've used another class as Dependency Injection is it good to work around or I've messed up the OOP way.
Helper.php
class Helper {
public function getModulePermission($role_id, $module, $type) {
// my work code
}
}
DesignationController.php
use App\Helpers\Helper;
class DesignationController extends Controller {
protected $designation;
protected $helper;
/**
* #param DesignationContract $designation
* #param Helper $helper
*/
public function __construct(DesignationContract $designation, Helper $helper) {
$this->designation = $designation;
$this->helper = $helper;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index(Request $request) {
$permission = $this->helper->getModulePermission($request->id, 'Designation', 'view');
if ($permission) {
return true;
} else {
return view('errors.forbidden');
}
}
So I've a class named Helper which can be accessed within each and every controller for checking permissions but I thought that I've messed up the OOP functionality over here. Is it good to work like it as or I need to create an Interface instead of class
Those are two different OOP concepts. the interface forces whoever class implement it to implement functions stated in the interface (called function signature). So for multiple classes implement the same interface, you will end up with multiple classes implement the same set of functions (wither it is the same function body or not).
The second concept is called, dependency injection or inversion of control in some cases. you inject a class either via class constructor or via setters and you call certain function provided by the injected class. Here you will have the same function called by multiple classes which is good for less modification by using common (injected) class, easier unit-testing (you can mock objects easily), more modular code (you can inject different class if you want different functionality).
So the current situation is good enough but it all depends in what you want to do which stated above.
I don't like the name, it speaks nothing to me or gives me an idea that this class can help me get the permissions of the module. Moreover, with a name like this, one can simply put another method, like lets say Helper::login($id) or you name it, which will instantly break the single responsibility principle (laravel controllers do that anyway).
The injection is relatively OK, perhaps a middleware class would be better place to do that.
I am using a framework that allows adding new components to the framework's base class. Is there any way to document these new methods without changing the frameworks files so I can click through to the method in my IDE.
I highly recommend against trying to inject a subclass. If the framework instantiates the class you're extending directly, you'll need to find a way to get it to use your subclass instead.
NetBeans and PhpStorm (and probably many others) will combine elements from multiple definitions of the same class/interface. This allows you to add properties and methods to any existing class without modifying the original source.
/**
* Framework controller base class.
* Provides helpers via __call().
*/
class Framework_Controller { ... }
Now create a file in your code base that you never require containing the same class definition. Your IDE should still parse it and merge its elements with the class above:
if (false) { // Safety first!
/**
* ACME Co. controller base class.
*
* #method ACME_Model_User getUser Load user via authentication helper
*/
class Framework_Controller { /* nothing to add */ }
}
You can try using an interface and declaring the methods normally instead of with #method. That is what we did with Zend_View since it's already an interface. I haven't tried mixing class with interface to see if PhpStorm likes it.
It depends mainly on IDE you are using. I think you should extend base class and add there some new methods/properties with phpdoc comments. Of course changing framework's files is no solution as you already mentioned
You could extend the original class, redefine the function, with new doc, and call the parent function.
e.g.
class newClass extends originalClass
{
/**
* New PHPDoc
*/
function functionName($a)
{
return parent::functionName($a);
}
}
Try to use #see or inline #link directives.
I need an advice for my simple project. It's a logger system. I have the following files/classes
File - check if file exist is readable etc
ConfigParser - it's an abstract class of which I use the __construct method to do some things. The class is never instantiated directly. It's a decorator.
abstract class ConfigParser
{
protected $filename;
public function __construct($file)
{
// Here I want to invoke validate() method of File class
// I know that I can do $file = new File(); $file->validate()
// but the idea is to keep the things decoupled
// Also I know that I can extend the File class ConfigParser extends File
// but this doesn't make sence
// I can pass the File object on child class new XmlParser('file.xml', $fileObj)
// but this doesn't make sence too.
// I don't want to use traits as it's bizarre for me
}
}
XmlParser - extends ConfigParser
IniParser - extends ConfigParser
As the project goal is to keep the classes decoupled I can't figure out how to implement the File class in this scenario.
I don't think it's such a nice design to do the validation in the constructor. A constructor should simply create the Parser and possibly do simple things.
What you could do would be using the template method pattern, then do the validation in the parent class and delegate the real parsing to the actual parser class.
abstract class ConfigParser {
final function parse(){
$file->validate();
$this->conreteParse();
}
abstract function concreteParse();
}
Let's assume that we have module called 'UsersModule' with the following model in it:
class User extends CActiveRecord
{
// Some code here
}
We use this module in different applications and some time we want to extend User model to add some custom methods or properties to it. More over, often we want to change tables in database to store this new properties in it. But we don't want to change code in the UsersModule itself because it comes from the master repository (GitHub for ex.) and when we fix some bugs in it we want to simply update this module from repository in all our projects. At the same time we want to save custom changes made for the projects. So we have the following idea:
In UsersModule.php we do the following:
class UsersModule extends CWebModule
{
public $usersBaseClass = 'UsersBase';
}
In Users.php:
$extendClass = Yii::app()->getModule('users')->usersBaseClass;
$version = '1.0';
$usersFile = Yii::getPathOfAlias('application.runtime').'/Users_extends_'.$extendClass.'_v'.$version.'.php';
if(!file_exists($usersFile)) {
$code =<<<PHP
<?php
/**
* This is the model class for table "{{users}}".
*/
class Users extends {$extendClass}
{
/**
* Returns the static model of the specified AR class.
* #param string \$className active record class name.
* #return Users the static model class
*/
public static function model(\$className=__CLASS__)
{
return parent::model(\$className);
}
}
PHP;
file_put_contents($usersFile, $code);
}
if(!class_exists('Users', flase))
require_once($usersFile);
Also we introduce UsersBase.php:
class UsersBase extends CActiveRecord
{
// All base Users model logic is here
}
So when we use Users class somewhere in our application our code in Users.php generates real Users class that extends desired base class. In each project when we want to extend our Users model we can do the following:
In configs/main.php of the project:
'modules' =>
'users => array(
'usersBaseClass' => 'MyUsers'
)
And also we add MyUsers.php some where in our application:
class MyUsers extends UsersBase
{
// All the custom logic goes here
}
So my question is:
Is it a good idea to generate classes automatically in runtime or not?
Genrating php code during runtime could work, but not the best solution imho. You should use some kind of table inheritance.
More info:
http://www.yiiframework.com/wiki/198/single-table-inheritance/
http://learnyii.blogspot.hu/2012/04/yii-table-inheritance-single-active.html
Basically I'm looking for feedback or guidance on something I've created this week at work. The problem was that I had two types of document upload. These types both shared methods like upload, isUploaded, move etc. But, in some instances they both had unique functionality.
So I thought the best approach to handle this would be to create an abstract class which contains the common functionality and 2 separate classes which extend the base abstract class in order to inherit the common functionality.
So I have:
abstract class Upload {
protected $_id;
protected $_name;
protected $_dbTable;
abstract public function create(Filter $filter) {}
abstract public function update(Filter $filter) {}
public function __construct($id){
if(!is_null($id)){
$class = new get_called_class();
return new $class($id);
}
}
protected function upload(){
//Code implemented
}
protected function isUploaded(){
//Code implemented
}
protected function move(){
//Code implemented
}
}
Class Book_Upload extends Upload {
$dbTable = 'book';
public function __construct($id){
//Database stuff to obtain record information
//Set protected member variables
$results = $databaseCall();
$this->_id = $results['id'];
$this->_name = $results['name'];
}
public function create(Filter $filter) {
//Code implemented
}
public function update(Filter $filter) {
//Code implemenetd
}
//Other unique functions
}
Class Magazine_Upload extends Upload {
$dbTable = 'magazine';
Same as Booking_Upload but with additional functionality
plus abstract methods
}
My query is, am I using abstract methods correctly? Have I followed the correct path. Also, I'm not sure I need the construct in the abstract class. What if someone attempts to call $upload = new Upload($id)?
Any class should provide a single type of functionality (Single Responsibility Principle, example: Single Responsibility Principle - A hard to see example?).
An upload class must only deal with uploads. Without more code, I smell an over-functional class from your words that tries to accomplish both the upload and document-spesific tasks.
So before going that way, you should define well what these classes will be doing. Are those document-spesific functionalities really related to the actual act of uploading?
You're extending class doesn't call parent::__construct() so the abstract __construct won't make any difference.
You are using abstract classes correctly; they are base classes that are to be built upon by other classes that share common functions and/or will have the same functionality but is implemented differently.
Abstract classes are a base to be built upon that provide common functionality and structure to other classes.