Consider the following situation:
A CSV file gets generated from some data with lines like this:
011111;1;1000221;014501;100;343;0;0;0,085;8,5;0;0;0,075;7,5;0;0;0;0
There's a lot more fields and fields are added every once in a while.
The code generating each line is a function of 240 lines.
Now I want to refactor this code in a way that each column will get its own object with it's own logic encapsulated in every object. It would make adding new columns easier and the code more readable.
But what pattern to use here? Composite or Decorator?
Decorator because there's a basic line already and it could get "decorated" with extra columns.
And composite because every line is "composed" of all columns.
What would be a better choice?
If your columns have complex logic for evaluating and you wan't to accord to SOLID principles (especially the Open/Closed Principle) you could make a base class or interface for your columns, with an "EvaluateValue" method. Than you are able to add new columns by deriving new classes, without changing the existing code. Only the initializer that instantiates all columns must be extended by a new line (appending the new column) but this is less error prone than adding something in 240 lines of code. You could use some IoC/DI Container to create all Column instances as well to avoid this.
Related
Both Filter and Interpreter Design Patterns look like much similar task oriented. Filter does filtering a list for some criteria, while Interpreter is doing pretty much same for a single element.
But I wonder why Filter is Structural and Interpreter is behavioral. Anyone got an idea?
Although it is true that they are "task-oriented", these two patterns actually refer to different purposes, let's take the example of an SQLTable class.
Filter pattern can serve to filter/remove/hide, more generally affect the structure of your database but don't modify its behavior at all.
Example 1 : Once filtered, it's only a new SQLTable with less/more rows and maybe less/more columns
Interpreter pattern belongs to behavioral pattern, in the sense that it modifes the behavior of an object (often represented with the help of a structural pattern such as Composite). The difference lies in the interpretation of the structure to behave differently.
Example 2: Once interpreted as a csv-table, your SQLTable can now be exported to a PDF file
I guess your misunderstanding comes from the fact that they are both applied to a structure in order to create something else but the actual difference lies in their intent rather than their concrete implementation which are relatively close in practice
I'm working with threedimensional arrays and it would be neat if I could name the array dimensions. The question marks in the example below are giving me the idea that this is possible.
Is it, and if so, how does it work? I can't seem to find it anywhere.
The three question marks are showing you that this array has three dimensions. If there was only one question mark, it would mean that the variable was declared as one dimensional. This is built in to VB and can't be change, as far as I know.
I think there's real value into making your code more readable and self-documenting. If I had a three dim array, I would probably create some custom class modules to model the objects that I was using.
If your first dimension is a SchoolID, your second dimension is a ClassID, and your third dimension is a StudentID, then code using custom class modules like this
Debug.Print Schools(10).Classes(3).Students(7).Name
is more readable than
Debug.Print arrLeeftijdenG5(10,3,7)
I don't know what you're storing, so it's just an example. Consider using custom class module to model the real-world objects your code is manipulating. There's a bit more set up involved, but it pays dividends down the road.
In my projects I often take advantage of tables and underlying ListObjects and ListColumns. I like them as they're easier to reference and update than bare Range objects. Yet I still haven't found a sane and maintainable way to handle multiple ListObjects consisting of many ListColumns and being referenced across all Worksheets in a project.
Let's say I have Worksheet (with (Name) property set to "WorksheetA") that contains table (called TableA) with few columns (called Column1, Column2, ..., Column10).
Now I want to reference one of the columns from the code of another Worksheet. I could do it as follows:
WorksheetA.ListObjects("TableA").ListColumns("Column7")
Now, it's a bad practice to use string directly, as it's difficult to maintain and prone to errors.
So what now?
I could create dedicated module to store my string as constants. For example, module called "Constants":
Public Const TABLE_A As String = "TableA"
Public Const COLUMN7 As String = "Column7"
Then my reference could be converted to:
WorksheetA.ListObjects(Constants.TABLE_A).ListColumns(Constants.COLUMN7)
However, this solution has some disadvantages:
Constants module would grow ridiculously fast with each table and column added.
Reference itself grows and becomes less readable.
All constants related to tables from across all workbooks are thrown into one giant pit.
I could store constants inside WorksheetA, and make them available through Public Functions like:
Private Const TABLE_A As String = "TableA"
Private Const COLUMN7 As String = "Column7"
Public Function GetTableAName() As String
GetTableAName = TABLE_A
End Function
Public Function GetTableA() As ListObject
Set GetTableA = WorksheetA.ListObjects(TABLE_A)
End Function
Public Function GetTableAColumn7() As ListColumn
Set GetTableAColumn7 = GetTableA().ListColumns(COLUMN7)
End Function
This solution actually solves all three problems mentioned above, yet it's still a bit "dirty" and time-consuming, as adding a new table introduces a requirement to create a function for each column.
Do you have better idea how to deal with this problem?
EDIT1 (for clarity): Let's assume that user must not change any names (neither table names nor column names). If user does so, it is he/she to blame.
EDIT2 (for clarity): I've used Column7 as column name only as an example. Let's assume that columns have more meaningful names.
Here's my two cents. I'm not an educated programmer, but I do get paid to do it, so I guess it makes me professional.
The first line of defense is that I create a class to model a table. I fill the class from the table and no other code even knows where the data lives. When I initialize, I'll run code like
clsEmployees.FillFromListObject wshEmployees.ListObjects(1)
Then in the class, the code looks like
vaData = lo.DataBodyRange.Value
...
clsEmployee.EeName = vaData(i,1)
clsEmployee.Ssn = vaData(i,2)
etc
Only one ListObject per worksheet. That's my rule and I never break it. Anyone with access to the worksheet could rearrange the columns and break my code. If I want to use Excel as a database, and sometimes I do, then that is the risk I take. If it's so critical that I can't take that risk, then I store my data in SQL Server, SQLite, or JET.
Instead of putting the range in an array, I could actually call out the ListColumns names. That way if someone rearranged the columns, my code will still work. But it introduces that they could rename the columns, so I'm just trading one risk for another. It would make the code more readable, so it may be the trade you want to make. I like the speed of filling from an array, so that's the trade I make.
If my project is sufficiently small or is supposed to work directly with ListObjects, then I follow the same rules as I do for any Strings.
I use Strings in code exactly once.
If I uses it more than once, I make a procedure-level constant
If I use it in more than one procedure, I try to pass it as an argument
If I can't pass it as an argument, I make a module-level constant
If the two procedures are in different modules, I first ask myself why two procedures are in different modules that use the same constant. Shouldn't related procedures be in the same module?
If the two procedures really belong in the different modules, then I try to pass it as an argument
If none of that works, then it truly is a global constant and I set up in my MGlobals module.
If MGlobals takes up more than about half a screen, I'm doing something wrong and I need to step back and think through what I'm trying to accomplish. And then I make a custom class.
Let's say in my domain I have a Money(amount, Currency(name)) value object (for example: new Money(1000, new Currency('USD'))).
However in my presentation layer (and only there really) I don't want to use USD currency name, but symbol ($) instead.
I don't want to overload my value object with presentation properties (since besides symbol there can be also such things as placement).
How do you guys handle this kind of mappings? Should I create some kind of CurrencyPropertyInMemoryRepository and fetch all info from there? What are my options?
I understand your concern that you want to separate this presentation aspect from your domain data, and if you want to go that way, I think using a repository for mapping the currency name to its symbol might be a good solution (retrieving the correct symbol could then be done in a ValueConverter for example that transforms your model data before they are presented in your UI).
But I personally would not have an issue by storing this additional symbol information also in the currency value object, for two reasons:
The currency symbol is highly related to the currency itself, so whenever the currency name changes, the symbol might also change. Therefore it would make sense to have both information stored in the same place or at least quite close to each other. When using an additional repository, your information is spread at least over two places.
If you have both information within your value object, you could also put additional behavior in your value object (e.g. not every currency has a symbol, in that case you need some logic to decide what to print instead).
I essentially have a database layer that is totally isolated from any business logic. This means that whenever I get ready to commit some business data to a database, I have to pass all of the business properties into the data method's parameter. For example:
Public Function Commit(foo as object) as Boolean
This works fine, but when I get into commits and updates that take dozens of parameters, it can be a lot of typing. Not to mention that two of my methods--update and create--take the same parameters since they essentially do the same thing. What I'm wondering is, what would be an optimal solution for passing these parameters so that I don't have to change the parameters in both methods every time something changes as well as reduce my typing :) I've thought of a few possible solutions. One would be to move all the sql parameters to the class level of the data class and then store them in some sort of array that I set in the business layer. Any help would be useful!
So essentially you want to pass in a List of Parameters?
Why not redo your Commit function and have it accept a List of Parameter objects?
If your on SQL 2008 you can use merge to replace insert / update juggling. Sometimes called upsert.
You could create a struct to hold the parameter values.
Thanks for the responses, but I think I've figured out a better way for what I'm doing. It's similar to using the upsert, but what I do is have one method called Commit that looks for the given primary key. If the record is found in the database, then I execute an update command. If not, I do an insert command. Since the parameters are the same, you don't have to worry about changing them any.
For your problem I guess Iterator design pattern is the best solution. Pass in an Interface implementation say ICommitableValues you can pass in a key pair enumeration value like this. Keys are the column names and values are the column commitable values. A property is even dedicated as to return the table name in which to insert these value and or store procedures etc.
To save typing you can use declarative programming syntax (Attributes) to declare the commitable properties and a main class in middleware can use reflection to extract the values of these commitable properties and prepare a ICommitableEnumeration implementation from it.