Factory hierarchy for creating GoogleMap and its elements
up vote
0
down vote
favorite
The purpose of this code is to create a GoogleMap using PHP, add markers to it according to Place
objects from database, add infoWindows for these markers. While reading about Factory pattern I came up with the following solution. What are the parts that can be improved. Thank you.
Factory for creating markers:
class MarkerFactory
{
public function create(Coordinate $position, array $options = )
{
$marker = new Marker($position);
$marker->setOptions($options);
return $marker;
}
}
Factory for creating infoWindows. Isn't it violating any principles because of injected dependency?
class InfoWindowFactory
{
private $twig;
public function __construct(Twig_Environment $twig)
{
$this->twig = $twig;
}
public function create(Place $place, $editable = false)
{
return new InfoWindow($this->renderWindowContent($place, $editable));
}
protected function renderWindowContent(Place $place, $editable)
{
if ($editable) {
$template = 'editable_infowindow.html.twig';
} else {
$template = 'static_infowindow.html.twig';
}
return $this->twig->render($template, ['place' => $place]);
}
}
MapFactory that uses MarkerFactory
and InfoWindowFactory
:
class MapFactory
{
private $markerFactory;
private $infoWindowFactory;
public function __construct(MarkerFactory $markerFactory, InfoWindowFactory $infoWindowFactory)
{
$this->markerFactory = $markerFactory;
$this->infoWindowFactory = $infoWindowFactory;
}
public function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = $this->markerFactory->create($position);
$infoWindow = $this->infoWindowFactory->create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
And the code example of usage:
$markerFactory = new MarkerFactory();
$infoWindowFactory = new InfoWindowFactory($this->get('twig'));
$mapFactory = new MapFactory($markerFactory, $infoWindowFactory);
$center = new Coordinate(55.117100, 23.940332);
$options = ['zoom' => 7];
$map = $mapFactory->create($center, $places, $options);
php factory-method google-maps
add a comment |
up vote
0
down vote
favorite
The purpose of this code is to create a GoogleMap using PHP, add markers to it according to Place
objects from database, add infoWindows for these markers. While reading about Factory pattern I came up with the following solution. What are the parts that can be improved. Thank you.
Factory for creating markers:
class MarkerFactory
{
public function create(Coordinate $position, array $options = )
{
$marker = new Marker($position);
$marker->setOptions($options);
return $marker;
}
}
Factory for creating infoWindows. Isn't it violating any principles because of injected dependency?
class InfoWindowFactory
{
private $twig;
public function __construct(Twig_Environment $twig)
{
$this->twig = $twig;
}
public function create(Place $place, $editable = false)
{
return new InfoWindow($this->renderWindowContent($place, $editable));
}
protected function renderWindowContent(Place $place, $editable)
{
if ($editable) {
$template = 'editable_infowindow.html.twig';
} else {
$template = 'static_infowindow.html.twig';
}
return $this->twig->render($template, ['place' => $place]);
}
}
MapFactory that uses MarkerFactory
and InfoWindowFactory
:
class MapFactory
{
private $markerFactory;
private $infoWindowFactory;
public function __construct(MarkerFactory $markerFactory, InfoWindowFactory $infoWindowFactory)
{
$this->markerFactory = $markerFactory;
$this->infoWindowFactory = $infoWindowFactory;
}
public function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = $this->markerFactory->create($position);
$infoWindow = $this->infoWindowFactory->create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
And the code example of usage:
$markerFactory = new MarkerFactory();
$infoWindowFactory = new InfoWindowFactory($this->get('twig'));
$mapFactory = new MapFactory($markerFactory, $infoWindowFactory);
$center = new Coordinate(55.117100, 23.940332);
$options = ['zoom' => 7];
$map = $mapFactory->create($center, $places, $options);
php factory-method google-maps
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
The purpose of this code is to create a GoogleMap using PHP, add markers to it according to Place
objects from database, add infoWindows for these markers. While reading about Factory pattern I came up with the following solution. What are the parts that can be improved. Thank you.
Factory for creating markers:
class MarkerFactory
{
public function create(Coordinate $position, array $options = )
{
$marker = new Marker($position);
$marker->setOptions($options);
return $marker;
}
}
Factory for creating infoWindows. Isn't it violating any principles because of injected dependency?
class InfoWindowFactory
{
private $twig;
public function __construct(Twig_Environment $twig)
{
$this->twig = $twig;
}
public function create(Place $place, $editable = false)
{
return new InfoWindow($this->renderWindowContent($place, $editable));
}
protected function renderWindowContent(Place $place, $editable)
{
if ($editable) {
$template = 'editable_infowindow.html.twig';
} else {
$template = 'static_infowindow.html.twig';
}
return $this->twig->render($template, ['place' => $place]);
}
}
MapFactory that uses MarkerFactory
and InfoWindowFactory
:
class MapFactory
{
private $markerFactory;
private $infoWindowFactory;
public function __construct(MarkerFactory $markerFactory, InfoWindowFactory $infoWindowFactory)
{
$this->markerFactory = $markerFactory;
$this->infoWindowFactory = $infoWindowFactory;
}
public function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = $this->markerFactory->create($position);
$infoWindow = $this->infoWindowFactory->create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
And the code example of usage:
$markerFactory = new MarkerFactory();
$infoWindowFactory = new InfoWindowFactory($this->get('twig'));
$mapFactory = new MapFactory($markerFactory, $infoWindowFactory);
$center = new Coordinate(55.117100, 23.940332);
$options = ['zoom' => 7];
$map = $mapFactory->create($center, $places, $options);
php factory-method google-maps
The purpose of this code is to create a GoogleMap using PHP, add markers to it according to Place
objects from database, add infoWindows for these markers. While reading about Factory pattern I came up with the following solution. What are the parts that can be improved. Thank you.
Factory for creating markers:
class MarkerFactory
{
public function create(Coordinate $position, array $options = )
{
$marker = new Marker($position);
$marker->setOptions($options);
return $marker;
}
}
Factory for creating infoWindows. Isn't it violating any principles because of injected dependency?
class InfoWindowFactory
{
private $twig;
public function __construct(Twig_Environment $twig)
{
$this->twig = $twig;
}
public function create(Place $place, $editable = false)
{
return new InfoWindow($this->renderWindowContent($place, $editable));
}
protected function renderWindowContent(Place $place, $editable)
{
if ($editable) {
$template = 'editable_infowindow.html.twig';
} else {
$template = 'static_infowindow.html.twig';
}
return $this->twig->render($template, ['place' => $place]);
}
}
MapFactory that uses MarkerFactory
and InfoWindowFactory
:
class MapFactory
{
private $markerFactory;
private $infoWindowFactory;
public function __construct(MarkerFactory $markerFactory, InfoWindowFactory $infoWindowFactory)
{
$this->markerFactory = $markerFactory;
$this->infoWindowFactory = $infoWindowFactory;
}
public function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = $this->markerFactory->create($position);
$infoWindow = $this->infoWindowFactory->create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
And the code example of usage:
$markerFactory = new MarkerFactory();
$infoWindowFactory = new InfoWindowFactory($this->get('twig'));
$mapFactory = new MapFactory($markerFactory, $infoWindowFactory);
$center = new Coordinate(55.117100, 23.940332);
$options = ['zoom' => 7];
$map = $mapFactory->create($center, $places, $options);
php factory-method google-maps
php factory-method google-maps
edited Feb 28 at 0:11
200_success
127k15148412
127k15148412
asked Nov 4 '16 at 9:25
nn4n4s
1162
1162
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.
Your MarkerFactory class is close, just needing to have create()
method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.
But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory
probably should not have a method such as renderWindowContent()
on it. That would seem to be a method that should perhaps exist on the InfoWindow
itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).
I would like to see InfoWindowFactory be something like:
namespace YourNamespace;
abstract class InfoWindowFactory
{
public static final function create(
Place $place,
Twig_Environment $twig,
$template
) {
return new InfoWindow($place, $twig, $template);
}
}
Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.
My comments on MapFactory
would be similar to those for the InfoWindowFactory
. Namely, I would rather see a class like structured like this:
namespace YourNamespace;
use MarkerFactory;
use InfowindowFactory;
abstract class MapFactory
{
public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = MarkerFactory::create($position);
$infoWindow = InfoWindowFactory::create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
A comment about validation...
You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place
objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection
or similar, you could be ensured that everything in that collection is a valid Place
object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).
Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map
, InfoWindow
, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.
Map, Marker, InfoWindow are from 3rd party livb
– nn4n4s
Nov 4 '16 at 18:48
@nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push therenderWindowContent()
logic down intoInfoWindow
– Mike Brant
Nov 4 '16 at 21:18
Are there some other principles that would make this code more testable than static methods?
– nn4n4s
Nov 5 '16 at 4:25
@nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
– Mike Brant
Nov 7 '16 at 2:53
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.
Your MarkerFactory class is close, just needing to have create()
method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.
But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory
probably should not have a method such as renderWindowContent()
on it. That would seem to be a method that should perhaps exist on the InfoWindow
itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).
I would like to see InfoWindowFactory be something like:
namespace YourNamespace;
abstract class InfoWindowFactory
{
public static final function create(
Place $place,
Twig_Environment $twig,
$template
) {
return new InfoWindow($place, $twig, $template);
}
}
Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.
My comments on MapFactory
would be similar to those for the InfoWindowFactory
. Namely, I would rather see a class like structured like this:
namespace YourNamespace;
use MarkerFactory;
use InfowindowFactory;
abstract class MapFactory
{
public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = MarkerFactory::create($position);
$infoWindow = InfoWindowFactory::create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
A comment about validation...
You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place
objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection
or similar, you could be ensured that everything in that collection is a valid Place
object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).
Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map
, InfoWindow
, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.
Map, Marker, InfoWindow are from 3rd party livb
– nn4n4s
Nov 4 '16 at 18:48
@nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push therenderWindowContent()
logic down intoInfoWindow
– Mike Brant
Nov 4 '16 at 21:18
Are there some other principles that would make this code more testable than static methods?
– nn4n4s
Nov 5 '16 at 4:25
@nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
– Mike Brant
Nov 7 '16 at 2:53
add a comment |
up vote
0
down vote
I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.
Your MarkerFactory class is close, just needing to have create()
method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.
But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory
probably should not have a method such as renderWindowContent()
on it. That would seem to be a method that should perhaps exist on the InfoWindow
itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).
I would like to see InfoWindowFactory be something like:
namespace YourNamespace;
abstract class InfoWindowFactory
{
public static final function create(
Place $place,
Twig_Environment $twig,
$template
) {
return new InfoWindow($place, $twig, $template);
}
}
Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.
My comments on MapFactory
would be similar to those for the InfoWindowFactory
. Namely, I would rather see a class like structured like this:
namespace YourNamespace;
use MarkerFactory;
use InfowindowFactory;
abstract class MapFactory
{
public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = MarkerFactory::create($position);
$infoWindow = InfoWindowFactory::create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
A comment about validation...
You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place
objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection
or similar, you could be ensured that everything in that collection is a valid Place
object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).
Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map
, InfoWindow
, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.
Map, Marker, InfoWindow are from 3rd party livb
– nn4n4s
Nov 4 '16 at 18:48
@nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push therenderWindowContent()
logic down intoInfoWindow
– Mike Brant
Nov 4 '16 at 21:18
Are there some other principles that would make this code more testable than static methods?
– nn4n4s
Nov 5 '16 at 4:25
@nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
– Mike Brant
Nov 7 '16 at 2:53
add a comment |
up vote
0
down vote
up vote
0
down vote
I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.
Your MarkerFactory class is close, just needing to have create()
method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.
But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory
probably should not have a method such as renderWindowContent()
on it. That would seem to be a method that should perhaps exist on the InfoWindow
itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).
I would like to see InfoWindowFactory be something like:
namespace YourNamespace;
abstract class InfoWindowFactory
{
public static final function create(
Place $place,
Twig_Environment $twig,
$template
) {
return new InfoWindow($place, $twig, $template);
}
}
Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.
My comments on MapFactory
would be similar to those for the InfoWindowFactory
. Namely, I would rather see a class like structured like this:
namespace YourNamespace;
use MarkerFactory;
use InfowindowFactory;
abstract class MapFactory
{
public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = MarkerFactory::create($position);
$infoWindow = InfoWindowFactory::create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
A comment about validation...
You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place
objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection
or similar, you could be ensured that everything in that collection is a valid Place
object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).
Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map
, InfoWindow
, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.
I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.
Your MarkerFactory class is close, just needing to have create()
method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.
But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory
probably should not have a method such as renderWindowContent()
on it. That would seem to be a method that should perhaps exist on the InfoWindow
itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).
I would like to see InfoWindowFactory be something like:
namespace YourNamespace;
abstract class InfoWindowFactory
{
public static final function create(
Place $place,
Twig_Environment $twig,
$template
) {
return new InfoWindow($place, $twig, $template);
}
}
Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.
My comments on MapFactory
would be similar to those for the InfoWindowFactory
. Namely, I would rather see a class like structured like this:
namespace YourNamespace;
use MarkerFactory;
use InfowindowFactory;
abstract class MapFactory
{
public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();
$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);
$markers = ;
foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());
$marker = MarkerFactory::create($position);
$infoWindow = InfoWindowFactory::create($place, $isEditableMap);
$marker->setInfoWindow($infoWindow);
$markers = $marker;
}
$map->getOverlayManager()->setMarkers($markers);
return $map;
}
}
A comment about validation...
You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place
objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection
or similar, you could be ensured that everything in that collection is a valid Place
object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).
Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map
, InfoWindow
, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.
edited Nov 4 '16 at 15:22
answered Nov 4 '16 at 15:05
Mike Brant
8,723619
8,723619
Map, Marker, InfoWindow are from 3rd party livb
– nn4n4s
Nov 4 '16 at 18:48
@nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push therenderWindowContent()
logic down intoInfoWindow
– Mike Brant
Nov 4 '16 at 21:18
Are there some other principles that would make this code more testable than static methods?
– nn4n4s
Nov 5 '16 at 4:25
@nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
– Mike Brant
Nov 7 '16 at 2:53
add a comment |
Map, Marker, InfoWindow are from 3rd party livb
– nn4n4s
Nov 4 '16 at 18:48
@nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push therenderWindowContent()
logic down intoInfoWindow
– Mike Brant
Nov 4 '16 at 21:18
Are there some other principles that would make this code more testable than static methods?
– nn4n4s
Nov 5 '16 at 4:25
@nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
– Mike Brant
Nov 7 '16 at 2:53
Map, Marker, InfoWindow are from 3rd party livb
– nn4n4s
Nov 4 '16 at 18:48
Map, Marker, InfoWindow are from 3rd party livb
– nn4n4s
Nov 4 '16 at 18:48
@nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the
renderWindowContent()
logic down into InfoWindow
– Mike Brant
Nov 4 '16 at 21:18
@nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the
renderWindowContent()
logic down into InfoWindow
– Mike Brant
Nov 4 '16 at 21:18
Are there some other principles that would make this code more testable than static methods?
– nn4n4s
Nov 5 '16 at 4:25
Are there some other principles that would make this code more testable than static methods?
– nn4n4s
Nov 5 '16 at 4:25
@nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
– Mike Brant
Nov 7 '16 at 2:53
@nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
– Mike Brant
Nov 7 '16 at 2:53
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f146104%2ffactory-hierarchy-for-creating-googlemap-and-its-elements%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown