robotlegs: I have 2 views and mediators that have in common 1 thing how can I DRY it? - dry

I have 2 views that show lists that then uses a mediator to get data. but I want in some way to DRY it so I don't have to repeat my self 2 times for the same thing. how do I do it?
EDIT1(code):
[SkinPart(required="false")]
public var WOListsDDL:DropDownList;
// in partadded
case WOListsDDL:
// when the selected list is changed in the lists drop down list
WOListsDDL.addEventListener(IndexChangeEvent.CHANGE, _WOListsDDL_changeHandler);
WOListsDDL.dataProvider = new ArrayCollection();
WOListsDDL.labelField = 'title';
break;
//
protected function _WOListsDDL_changeHandler(event:*):void{
_debug('List selection changed handler.');
_getContentsForList();
}
protected function _getContentsForList():void{
_debug('Getting list items.');
getItemsSignal.dispatch({key: getSelectedList()._key, itemType: 'item'});
}
public var getItemsSignal:GetItemsSignal = new GetItemsSignal();
override public function mediatorComplete():void{
getItemsSignal.dispatch({key: tottysAuth.getCurrentUser()._key, itemType: 'list'});
}
// then in my mediator
[Inject] public var getItemsSignal:GetItemsSignal;
override public function onRegister():void{
// view listeners
view.getItemsSignal.add(_getItemsSignalHandler);
}
protected function _getItemsSignalHandler(input:Object):void{
getItemsSignal.dispatch(input);
}
this all for one view-mediator. now I have 2 view-mediators that are doing these tasks. How to make them dry?
Solutions I have:
make a little view containing the dropdown list with a mediator that is listening for the event. in the big components they are listening for a signal in the view of this little component. nothing more. it seems quite well but i don't think is so great

So there is functionality on both the views and the mediators that you'd like not to repeat?
You could put the code you want to reuse in another object and call its methods from your multiple views and mediators. Or you could put it in ancestor classes and extend each of those classes in both your view and your mediator.
Best practice would be to do the former and not the latter.

Related

How do I make a well designed validation for a complex collection model?

As input I have a list of Books. As output I expect a SimilarBookCollection.
A SimilarBookCollection has an author, publishYear and list of Books. The SimilarBookCollection can't be created if the author of the books is different or if the publishYear is different.
The solution so far in PHP:
client.php
----
$arrBook = array(...); // array of books
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
$objSimilarBookCollection = new SimilarBookCollection($arrBook);
echo $objSimilarBookCollection->GetAuthor();
}
else {
echo 'Invalid input';
}
SimilarBookCollection.php
---
class SimilarBookCollection() {
public function SimilarBookCollection(array $arrBook) {
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
throw new Exception('Invalid books to create collection');
}
$this->author = $arrBook[0]->GetAuthor();
$this->publishYear = $arrBook[0]->GetPublishYear();
$this->books = $arrBook;
}
public function GetAuthor() {
return $this->author;
}
public function GetPublishYear() {
return $this->publishYear;
}
public function GetBooks() {
return $this->books;
}
}
SimilarBookCollectionValidator.php
---
class SimilarBookCollectionValidator() {
public function IsValid() {
$this->ValidateAtLeastOneBook();
$this->ValidateSameAuthor();
$this->ValidateSameYear();
return $this->blnValid;
}
... //actual validation routines
}
The goal is to have a "special" collection with only books that have the same author and publishYear. The idea is to easily access the repeating information like author or year from the object.
How would you name the SimilarBookCollection? The current name is to
generic. Using a name like SameYearAuthorBookCollection looks a bit
long and strange(if more conditions will be added then name will increase)
Would you use a Validator in SimilarBookCollection constructor using a
defensive programming style?
Would you change the design of the code? If yes how?
It all depends ;)
So if I were to aim for a generic adaptable solution I would do the following:
Validator in constructor
On one hand you are validating twice; that is informative in case of a broken precondition/contract (not giving a valid list), but is double the code to run - for what purpose exactly?
If you want to use this in a system depends on its size, how critical it is, product phase, and likely more criterias.
But then it also is controller logic fitted into a model meaning you are spreading your code around.
I would not put it in the constructor.
Name / Design
I would say keep the BookCollection generic as it is, and have any validation strictly in the controller space, instead of bloating the collection which essentially seems to be an array with the extra field of author.
If you want to differentiate between different collection types use either (multiple) inheritance or some sort of additional field "collectionType"; the former if you expect many derivatives or varying functionality to come (also keeps the logic where different nicely separated).
You could also consider your collection as a set on which you perform queries and for convenience's sake you could maintain some sort of meta data like $AuthorCount = N, $publicationDates = array(...) from which you can quickly derive the collection's nature. This approach would also keep your validator-code minimal (or non-existent), as it'd be implicitly in the collection and you could just do the validation in the controller keeping the effective logic behind it clearly visible.
That would also make it more comfortable for you in the future. But the question really is what you want and need it for, and what changes you expect, because you are supposed to fit your design to your requirements and likely changes.
For your very particular problem the constraints as I understand are as follows:
There is only one collection type class in the system at any given
point in time.
The class's items have several attributes, and for a particular, possibly changing subset of these (called identical attributes), the collection only accepts item lists where the chosen attributes of all items are identical.
The class provides getters for all identical attributes
The class must not be usable in any other way than the intended way.
If not for point 1 I would use a generic base class that is either parametrized (ie you tell it upon instantiation which is the set of identical attributes) or uses multiple inheritance (or in php traits) to compose arbitrary combinations with the needed interfaces. Children might rely on the base class but use a predefined subset of the identical attributes.
The parametrized variant might look something as follows:
class BookCollection {
public function __construct($book_list, $identical_fields=array())
{
if (empty($book_list))
{
throw new EmptyCollectionException("Empty book list");
}
$default = $book_list[0];
$this->ia = array();
foreach($identical_fields as $f)
{
$this->ia[$f] = $default->$f;
}
foreach($book_list as $book)
{
foreach($identical_fields as $f)
{
if ($this->ia[$f] !== $book->$f)
{
throw new NotIdenticalFieldException("Field $f is not identical for all");
}
}
}
$this->book_list = $book_list;
}
public function getIdentical($key)
{
$this->ia[$key];
}
}
final class BC_by_Author extends BookCollection{
public function __construct($book_list)
{
parent::__construct($book_list,array('author'));
}
public function getAuthor(){ $this->ia['author']; }
}
or fooling around with abstract and final types (not sure if it's valid like this)
abstract class BookCollection{
public final function __construct($book_list){...}
abstract public function getIdenticalAttributes();
}
final class BC_by_Author {
public function getIdenticalAttributes(){ return array('author'); }
public function getAuthor(){ return $this->ia['author']; }
}
If you rely on getters that do not necessarily match the field names I would go for multiple inheritance/traits.
The naming then would be something like BC_Field1Field2Field3.
Alternatively or additionally, you could also use exactly the same classname but develop your solutions in different namespaces, which would mean you wouldn't have to change your code when you change the namespace, plus you can keep it short in the controllers.
But because there will only ever be one class, I would name it BookCollection and not unnecessarily discuss it any further.
Because of constraint 4, the white box constraint, the given book list must be validated by the class itself, ie in the constructor.

Connecting data to a GUI - OOP

I have an application with several graphs and tables on it.
I worked fast and just made classes like Graph and Table that each contained a request object (pseudo-code):
class Graph {
private request;
public function setDateRange(dateRange) {
request.setDateRange(dateRange);
}
public function refresh() {
request.getData(function() {
//refresh the display
});
}
}
Upon a GUI event (say, someone changes the date range dropdown), I'd just call the setters on the Graph instance and then refresh it. Well, when I added other GUI elements like tables and whatnot, they all basically had similar methods (setDateRange and other things common to the request).
What are some more elegant OOP ways of doing this?
The application is very simple and I don't want to over-architect it, but I also don't want to have a bunch of classes with basically the same methods that are just routing to a request object. I also don't want to set up each GUI class as inheriting from the request class, but I'm open to any ideas really.
As you commented the methods are identical. In that case I would suggest the following approach.
abstract class AbstractGUIElement {
protected request;
public function setDateRange(dateRange) {
request.setDateRange(dateRange);
}
abstract function refresh();
}
Refreshing would probably be element specific so I have added it as an abstract method the inheriting types have to implement.
class Graph extends AbstractGUIElement {
public function refresh() {
// Graph specific refreshing
}
}

Yii: attaching events to models

I have a User model which is bundled in a module installed on my Yii application. This module is third party and I do not want to alter its code.
I also have a Cv Model that has a BELONGS_TO relation with the User model.
My question is: How can I delete the cv when a user is deleted ?
I know that I can achieve this with on delete cascade ... on mysql. However, i do need to delete other data such as a photo, files, etc.
What I have tried
I have created a component that is preloaded on my application. This component attaches to an onAfterDelete event
class EventListener extends CComponent
{
public function init() {
Yii::import("application.modules.users.models.User");
User::model()->attachEventHandler('onAfterDelete', array($this, 'deleteUser'));
}
public function deleteUser($event)
{
// stuff here ...
}
}
However this does not work.
Any suggestions ?
This may help you.
User::model() is a singleton
$user1 = User::model();
$user2 = new User; // will be used in insert action
$user3 = User::model()->findByPk(10); // will be used in update/delete action
$user1, $user2 and $user3 are completely different objects.
You can attach events to objects, in this case you have to add events to all these 3 objects individually.
$user1->attachEventHandler(...);
$user2->attachEventHandler(...);
$user3->attachEventHandler(...);
look like Yii does not provide any way to add events at Class level.
Well, guys, I have just stumbled upon the same problem and I solved it this way:
You should use the init() of a Model, not your event listener collection class.
In my case I have devModel class:
public function init()
{
parent::init();
$this->onLicenseUpdated = array(new MEventProcessor, 'licenseUpdateHandler');
}
And the handler is licenseUpdateHandler($event) in a MEventProcessor class.
This way every time you work with model instance, it'll call init() for every object and attach the event handler to every instance of this Model.
Now any time the event (in my case onLicenseUpdated()) is invoked for the model - the handler will be called too.
You could also to use Behaviors.
1 - behaviors can listen to events : you just have to override their events() method
class MyBehavior extends Behavior {
public function events() {
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event) {
// ...
}
}
2 - although it is more common to attach a behavior to a component in the component's behaviors() method, you can also attach them dynamically and keep the original code unmodified :
use app\components\MyBehavior;
// attach a behavior object
$component->attachBehavior('myBehavior1', new MyBehavior);
You will find some useful documentation here :
yii 1 : http://www.yiiframework.com/doc/api/1.1/CBehavior
yii 2 : http://www.yiiframework.com/doc-2.0/guide-concept-behaviors.html

Law of Demeter - Data objects

I'm trying to follow the Law Of Demeter ( see http://en.wikipedia.org/wiki/Law_of_Demeter , http://misko.hevery.com/code-reviewers-guide/flaw-digging-into-collaborators/ ) as I can see the benefits, however I've become a little stuck when it comes to domain objects.
Domain objects do naturally have a chain and sometimes it's necessary to display the information about the entire chain.
For instance, a shopping basket:
Each order contains a user, delivery info and a list of items
Each order item contains a product and quantity
Each product has a name and price.
Each user contains a name and address
The code which displays the order information has to use all the information about the order, users and products.
Surely it's better and more reusable to get this information through the order object e.g. "order.user.address.city" than for some code higher up to do queries for all the objects I listed above then pass them into the code separately?
Any comments/suggestions/tips are welcome!
One problem with using chained references, such as order.user.address.city, is that higher-order dependencies get "baked into" the structure of code outside the class.
Ideally, in cases when you refactor your class, your "forced changes" should be limited to the methods of the class being refactored. When you have multiple chained references in the client code, refactoring drives you to make changes in other places of your code.
Consider an example: suppose that you'd like to replace User with an OrderPlacingParty, an abstraction encapsulating users, companies, and electronic agents that can place an order. This refactoring immediately presents multiple problems:
The User property will be called something else, and it will have a different type
The new property may not have an address that has city in cases when the order is placed by an electronic agent
The human User associated with the order (suppose that your system needs one for legal reasons) may be related to the order indirectly, - for example, by being a designated go-to person in the definition of the OrderPlacingParty.
A solution to these problems would be to pass the order presentation logic everything that it needs directly, rather than having it "understand" the structure of the objects passed in. This way you would be able to localize the changes to the code being refactored, without spreading the changes to other code that is potentially stable.
interface OrderPresenter {
void present(Order order, User user, Address address);
}
interface Address {
...
}
class PhysicalAddress implements Address {
public String getStreetNumber();
public String getCity();
public String getState();
public String getCountry();
}
class ElectronicAddress implements Address {
public URL getUrl();
}
interface OrderPlacingParty {
Address getAddress();
}
interface Order {
OrderPlacingParty getParty();
}
class User implements OrderPlacingParty {
}
class Company implements OrderPlacingParty {
public User getResponsibleUser();
}
class ElectronicAgent implements OrderPlacingParty {
public User getResponsibleUser();
}
I think, when chaining is used to access some property, it is done in two (or at least two) different situation. One is the case that you have mentioned, for example, in your presentation module, you have an Order object and you would like to just display the owner's/user's address, or details like city. In that case, I think it is of not much problem if you do so. Why? Because you are not performing any business logic on the accessed property, which can (potentially) cause tight coupling.
But, things are different if you use such chaining for the purpose of performing some logic on the accessed property. For example, if you have,
String city = order.user.address.city;
...
order.user.address.city = "New York";
This is problematic. Because, this logic is/should more appropriately be performed in a module closer to the target attribute - city. Like, in a place where the Address object is constructed in the first place, or if not that, at least when the User object is constructed (if say User is the entity and address the value type). But, if it goes farther than that, the farther it goes, the more illogical and problematic it becomes. Because there are too many intermediaries are involved between the source and the target.
Thus, according to the the Law of Demeter, if you are performing some logic on the "city" attribute in a class, say OrderAssmebler, which accesses the city attribute in a chain like order.user.address.city, then you should think of moving this logic to a place/module closer to the target.
You're correct and you'll most likely model your value objects something like this
class Order {
User user;
}
class User {
Address shippingAddress;
Address deliveryAddress;
}
class Address {
String city;
...
}
When you start considering how you will persist this data to a database (e.g. ORM) do you start thinking about performance. Think eager vs lazy loading trade offs.
Generally speaking I adhere to the Law of Demeter since it helps to keep changes in a reduced scope, so that a new requirement or a bug fix doesn't spread all over your system. There are other design guidelines that help in this direction, e.g. the ones listed in this article. Having said that, I consider the Law of Demeter (as well as Design Patterns and other similar stuff) as helpful design guidelines that have their trade-offs and that you can break them if you judge it is ok to do so. For example I generally don't test private methods, mainly because it creates fragile tests. However, in some very particular cases I did test an object private method because I considered it to be very important in my app, knowing that that particular test will be subject to changes if the implementation of the object changed. Of course in those cases you have to be extra careful and leave more documentation for other developers explaining why you are doing that. But, in the end, you have to use your good judgement :).
Now, back to the original question. As far as I understand your problem here is writing the (web?) GUI for an object that is the root of a graph of objects that can be accessed through message chains. For that case I would modularize the GUI in a similar way that you created your model, by assigning a view component for each object of your model. As a result you would have classes like OrderView, AddressView, etc that know how to create the HTML for their respective models. You can then compose those views to create your final layout, either by delegating the responsibility to them (e.g. the OrderView creates the AddressView) or by having a Mediator that takes care of composing them and linking them to your model. As an example of the first approach you could have something like this (I'll use PHP for the example, I don't know which language you are using):
class ShoppingBasket
{
protected $orders;
protected $id;
public function getOrders(){...}
public function getId(){...}
}
class Order
{
protected $user;
public function getUser(){...}
}
class User
{
protected $address;
public function getAddress(){...}
}
and then the views:
class ShoppingBasketView
{
protected $basket;
protected $orderViews;
public function __construct($basket)
{
$this->basket = $basket;
$this->orederViews = array();
foreach ($basket->getOrders() as $order)
{
$this->orederViews[] = new OrderView($order);
}
}
public function render()
{
$contents = $this->renderBasketDetails();
$contents .= $this->renderOrders();
return $contents;
}
protected function renderBasketDetails()
{
//Return the HTML representing the basket details
return '<H1>Shopping basket (id=' . $this->basket->getId() .')</H1>';
}
protected function renderOrders()
{
$contents = '<div id="orders">';
foreach ($this->orderViews as $orderView)
{
$contents .= orderViews->render();
}
$contents .= '</div>';
return $contents;
}
}
class OrderView
{
//The same basic pattern; store your domain model object
//and create the related sub-views
public function render()
{
$contents = $this->renderOrderDetails();
$contents .= $this->renderSubViews();
return $contents;
}
protected function renderOrderDetails()
{
//Return the HTML representing the order details
}
protected function renderOrders()
{
//Return the HTML representing the subviews by
//forwarding the render() message
}
}
and in your view.php you would do something like:
$basket = //Get the basket based on the session credentials
$view = new ShoppingBasketView($basket);
echo $view->render();
This approach is based on a component model, where the views are treated as composable components. In this schema you respect the object's boundaries and each view has a single responsibility.
Edit (Added based on the OP comment)
I'll assume that there is no way of organizing the views in subviews and that you need to render the basket id, order date and user name in a single line. As I said in the comment, for that case I would make sure that the "bad" access is performed in a single, well documented place, leaving the view unaware of this.
class MixedView
{
protected $basketId;
protected $orderDate;
protected $userName;
public function __construct($basketId, $orderDate, $userName)
{
//Set internal state
}
public function render()
{
return '<H2>' . $this->userName . "'s basket (" . $this->basketId . ")<H2> " .
'<p>Last order placed on: ' . $this->orderDate. '</p>';
}
}
class ViewBuilder
{
protected $basket;
public function __construct($basket)
{
$this->basket = $basket;
}
public function getView()
{
$basketId = $this->basket->getID();
$orderDate = $this->basket->getLastOrder()->getDate();
$userName = $this->basket->getUser()->getName();
return new MixedView($basketId, $orderDate, $userName);
}
}
If later on you rearrange your domain model and your ShoppingBasket class can't implement the getUser() message anymore then you will have to change a single point in your application, avoid having that change spread all over your system.
HTH
The Law Of Demeter is about calling methods, not accessing properties/fields. I know technically properties are methods, but logically they're meant to be data. So, your example of order.user.address.city seems fine to me.
This article is interesting further reading: http://haacked.com/archive/2009/07/13/law-of-demeter-dot-counting.aspx

Alternative to the visitor pattern?

I am looking for an alternative to the visitor pattern. Let me just focus on a couple of pertinent aspects of the pattern, while skipping over unimportant details. I'll use a Shape example (sorry!):
You have a hierarchy of objects that implement the IShape interface
You have a number of global operations that are to be performed on all objects in the hierarchy, e.g. Draw, WriteToXml etc...
It is tempting to dive straight in and add a Draw() and WriteToXml() method to the IShape interface. This is not necessarily a good thing - whenever you wish to add a new operation that is to be performed on all shapes, each IShape-derived class must be changed
Implementing a visitor for each operation i.e. a Draw visitor or a WirteToXml visitor encapsulates all the code for that operation in one class. Adding a new operation is then a matter of creating a new visitor class that performs the operation on all types of IShape
When you need to add a new IShape-derived class, you essentially have the same problem as you did in 3 - all visitor classes must be changed to add a method to handle the new IShape-derived type
Most places where you read about the visitor pattern state that point 5 is pretty much the main criteria for the pattern to work and I totally agree. If the number of IShape-derived classes is fixed, then this can be a quite elegant approach.
So, the problem is when a new IShape-derived class is added - each visitor implementation needs to add a new method to handle that class. This is, at best, unpleasant and, at worst, not possible and shows that this pattern is not really designed to cope with such changes.
So, the question is has anybody come across alterative approaches to handling this situation?
You might want to have a look at the Strategy pattern. This still gives you a separation of concerns while still being able to add new functionality without having to change each class in your hierarchy.
class AbstractShape
{
IXmlWriter _xmlWriter = null;
IShapeDrawer _shapeDrawer = null;
public AbstractShape(IXmlWriter xmlWriter,
IShapeDrawer drawer)
{
_xmlWriter = xmlWriter;
_shapeDrawer = drawer;
}
//...
public void WriteToXml(IStream stream)
{
_xmlWriter.Write(this, stream);
}
public void Draw()
{
_drawer.Draw(this);
}
// any operation could easily be injected and executed
// on this object at run-time
public void Execute(IGeneralStrategy generalOperation)
{
generalOperation.Execute(this);
}
}
More information is in this related discussion:
Should an object write itself out to a file, or should another object act on it to perform I/O?
There is the "Visitor Pattern With Default", in which you do the visitor pattern as normal but then define an abstract class that implements your IShapeVisitor class by delegating everything to an abstract method with the signature visitDefault(IShape).
Then, when you define a visitor, extend this abstract class instead of implementing the interface directly. You can override the visit* methods you know about at that time, and provide for a sensible default. However, if there really isn't any way to figure out sensible default behavior ahead of time, you should just implement the interface directly.
When you add a new IShape subclass, then, you fix the abstract class to delegate to its visitDefault method, and every visitor that specified a default behavior gets that behavior for the new IShape.
A variation on this if your IShape classes fall naturally into a hierarchy is to make the abstract class delegate through several different methods; for example, an DefaultAnimalVisitor might do:
public abstract class DefaultAnimalVisitor implements IAnimalVisitor {
// The concrete animal classes we have so far: Lion, Tiger, Bear, Snake
public void visitLion(Lion l) { visitFeline(l); }
public void visitTiger(Tiger t) { visitFeline(t); }
public void visitBear(Bear b) { visitMammal(b); }
public void visitSnake(Snake s) { visitDefault(s); }
// Up the class hierarchy
public void visitFeline(Feline f) { visitMammal(f); }
public void visitMammal(Mammal m) { visitDefault(m); }
public abstract void visitDefault(Animal a);
}
This lets you define visitors that specify their behavior at whatever level of specificity you wish.
Unfortunately, there is no way to avoid doing something to specify how visitors will behave with a new class - either you can set up a default ahead of time, or you can't. (See also the second panel of this cartoon )
I maintain a CAD/CAM software for metal cutting machine. So I have some experience with this issues.
When we first converted our software (it was first released in 1985!) to a object oriented designed I did just what you don't like. Objects and Interfaces had Draw, WriteToFile, etc. Discovering and reading about Design Patterns midway through the conversion helped a lot but there were still a lot of bad code smells.
Eventually I realized that none of these types of operations were really the concern of the object. But rather the various subsystems that needed to do the various operations. I handled this by using what is now called a Passive View Command object, and well defined Interface between the layers of software.
Our software is structured basically like this
The Forms implementing various Form
Interface. These forms are a thing shell passing events to the UI Layer.
UI layer that receives Events and manipulate forms through the Form interface.
The UI Layer will execute commands that all implement the Command interface
The UI Object have interfaces of their own that the command can interact with.
The Commands get the information they need, process it, manipulates the model and then report back to the UI Objects which then does anything needed with the forms.
Finally the models which contains the various objects of our system. Like Shape Programs, Cutting Paths, Cutting Table, and Metal Sheets.
So Drawing is handled in the UI Layer. We have different software for different machines. So while all of our software share the same model and reuse many of the same commands. They handle things like drawing very different. For a example a cutting table is draw different for a router machine versus a machine using a plasma torch despite them both being esstentially a giant X-Y flat table. This because like cars the two machines are built differently enough so that there is a visual difference to the customer.
As for shapes what we do is as follows
We have shape programs that produce cutting paths through the entered parameters. The cutting path knows which shape program produced. However a cutting path isn't a shape. It just the information needed to draw on the screen and to cut the shape. One reason for this design is that cutting paths can be created without a shape program when they are imported from a external app.
This design allows us to separate the design of the cutting path from the design of the shape which are not always the same thing. In your case likely all you need to package is the information needed to draw the shape.
Each shape program has a number of views implementing a IShapeView Interface. Through the IShapeView interface the shape program can tell the generic shape form we have how to setup itself up to show the parameters of that shape. The generic shape form implements a IShapeForm interface and registers itself with the ShapeScreen Object. The ShapeScreen Object registers itself with our application object. The shape views use whatever shapescreen that registers itself with the application.
The reason for the multiple views that we have customers that like to enter shapes in different ways. Our customer base is split in half between those who like to enter shape parameters in a table form and those who like to enter with a graphical representation of the shape in front of them. We also need to access the parameters at times through a minimal dialog rather than our full shape entry screen. Hence the multiple views.
Commands that manipulate shapes fall in one of two catagories. Either they manipulate the cutting path or they manipulate the shape parameters. To manipulate the shape parameters generally we either throw them back into the shape entry screen or show the minimal dialog. Recalculate the shape, and display it in the same location.
For the cutting path we bundled up each operation in a separate command object. For example we have command objects
ResizePath
RotatePath
MovePath
SplitPath
and so on.
When we need to add new functionality we add another command object, find a menu, keyboard short or toolbar button slot in the right UI screen and setup the UI object to ececute that command.
For example
CuttingTableScreen.KeyRoute.Add vbShift+vbKeyF1, New MirrorPath
or
CuttingTableScreen.Toolbar("Edit Path").AddButton Application.Icons("MirrorPath"),"Mirror Path", New MirrorPath
In both instances the Command object MirrorPath is being associated with a desired UI element. In the execute method of MirrorPath is all the code needed to mirror the path in a particular axis. Likely the command will have it's own dialog or use one of the UI elements to ask the user which axis to mirror. None of this is making a visitor, or adding a method to the path.
You will find that a lot can be handled through bundling actions into commands. However I caution that is not a black or white situation. You will still find that certain things work better as methods on the original object. In may experience I found that perhaps 80% of what I used to do in methods were able to be moved into the command. The last 20% just plain work better on the object.
Now some may not like this because it seems to violate encapsulations. From maintaining our software as a object oriented system for the last decade I have to say the MOST important long term thing you can do is clearly document the interactions between the different layers of your software and between the different objects.
Bundling actions into Command objects helps with this goal way better than a slavish devotion to the ideals of encapsulation. Everything that is needs to be done to Mirror a Path is bundled in the Mirror Path Command Object.
Visitor design pattern is a workaround, not a solution to the problem. Short answer would be pattern matching.
Regardless of what path you take, the implementation of alternate functionality that is currently provided by the Visitor pattern will have to 'know' something about the concrete implementation of the interface that it is working on. So there is no getting around the fact that you are going to have to write addition 'visitor' functionality for each additional implementation. That said what you are looking for is a more flexible and structured approach to creating this functionality.
You need to separate out the visitor functionality from the interface of the shape.
What I would propose is a creationist approach via an abstract factory to create replacement implementations for visitor functionality.
public interface IShape {
// .. common shape interfaces
}
//
// This is an interface of a factory product that performs 'work' on the shape.
//
public interface IShapeWorker {
void process(IShape shape);
}
//
// This is the abstract factory that caters for all implementations of
// shape.
//
public interface IShapeWorkerFactory {
IShapeWorker build(IShape shape);
...
}
//
// In order to assemble a correct worker we need to create
// and implementation of the factory that links the Class of
// shape to an IShapeWorker implementation.
// To do this we implement an abstract class that implements IShapeWorkerFactory
//
public AbsractWorkerFactory implements IShapeWorkerFactory {
protected Hashtable map_ = null;
protected AbstractWorkerFactory() {
map_ = new Hashtable();
CreateWorkerMappings();
}
protected void AddMapping(Class c, IShapeWorker worker) {
map_.put(c, worker);
}
//
// Implement this method to add IShape implementations to IShapeWorker
// implementations.
//
protected abstract void CreateWorkerMappings();
public IShapeWorker build(IShape shape) {
return (IShapeWorker)map_.get(shape.getClass())
}
}
//
// An implementation that draws circles on graphics
//
public GraphicsCircleWorker implements IShapeWorker {
Graphics graphics_ = null;
public GraphicsCircleWorker(Graphics g) {
graphics_ = g;
}
public void process(IShape s) {
Circle circle = (Circle)s;
if( circle != null) {
// do something with it.
graphics_.doSomething();
}
}
}
//
// To replace the previous graphics visitor you create
// a GraphicsWorkderFactory that implements AbstractShapeFactory
// Adding mappings for those implementations of IShape that you are interested in.
//
public class GraphicsWorkerFactory implements AbstractShapeFactory {
Graphics graphics_ = null;
public GraphicsWorkerFactory(Graphics g) {
graphics_ = g;
}
protected void CreateWorkerMappings() {
AddMapping(Circle.class, new GraphicCircleWorker(graphics_));
}
}
//
// Now in your code you could do the following.
//
IShapeWorkerFactory factory = SelectAppropriateFactory();
//
// for each IShape in the heirarchy
//
for(IShape shape : shapeTreeFlattened) {
IShapeWorker worker = factory.build(shape);
if(worker != null)
worker.process(shape);
}
It still means that you have to write concrete implementations to work on new versions of 'shape' but because it is completely separated from the interface of shape, you can retrofit this solution without breaking the original interface and software that interacts with it. It acts as a sort of scaffolding around the implementations of IShape.
If you're using Java: Yes, it's called instanceof. People are overly scared to use it. Compared to the visitor pattern, it's generally faster, more straightforward, and not plagued by point #5.
If you have n IShapes and m operations that behave differently for each shape, then you require n*m individual functions. Putting these all in the same class seems like a terrible idea to me, giving you some sort of God object. So they should be grouped either by IShape, by putting m functions, one for each operation, in the IShape interface, or grouped by operation (by using the visitor pattern), by putting n functions, one for each IShape in each operation/visitor class.
You either have to update multiple classes when you add a new IShape or when you add a new operation, there is no way around it.
If you are looking for each operation to implement a default IShape function, then that would solve your problem, as in Daniel Martin's answer: https://stackoverflow.com/a/986034/1969638, although I would probably use overloading:
interface IVisitor
{
void visit(IShape shape);
void visit(Rectangle shape);
void visit(Circle shape);
}
interface IShape
{
//...
void accept(IVisitor visitor);
}
I have actually solved this problem using the following pattern. I do not know if it has a name or not!
public interface IShape
{
}
public interface ICircleShape : IShape
{
}
public interface ILineShape : IShape
{
}
public interface IShapeDrawer
{
void Draw(IShape shape);
/// <summary>
/// Returns the type of the shape this drawer is able to draw!
/// </summary>
Type SourceType { get; }
}
public sealed class LineShapeDrawer : IShapeDrawer
{
public Type SourceType => typeof(ILineShape);
public void Draw(IShape drawing)
{
if (drawing is ILineShape)
{
// Code to draw the line
}
}
}
public sealed class CircleShapeDrawer : IShapeDrawer
{
public Type SourceType => typeof(ICircleShape);
public void Draw(IShape drawing)
{
if (drawing is ICircleShape)
{
// Code to draw the circle
}
}
}
public sealed class ShapeDrawingClient
{
private readonly IDictionary<Type, IShapeDrawer> m_shapeDrawers =
new Dictionary<Type, IShapeDrawer>();
public void Add(IShapeDrawer shapeDrawer)
{
m_shapeDrawers[shapeDrawer.SourceType] = shapeDrawer;
}
public void Draw(IShape shape)
{
Type[] interfaces = shape.GetType().GetInterfaces();
foreach (Type #interface in interfaces)
{
if (m_shapeDrawers.TryGetValue(#interface, out IShapeDrawer drawer))
{
drawer.Draw(drawing);
return;
}
}
}
}
Usage:
LineShapeDrawer lineShapeDrawer = new LineShapeDrawer();
CircleShapeDrawer circleShapeDrawer = new CircleShapeDrawer();
ShapeDrawingClient client = new ShapeDrawingClient ();
client.Add(lineShapeDrawer);
client.Add(circleShapeDrawer);
foreach (IShape shape in shapes)
{
client.Draw(shape);
}
Now if someone as the user of my library defines IRectangleShape and wants to draw it, they can simply define IRectangleShapeDrawer and add it to ShapeDrawingClient's list of drawers!