Twoje komentarze
Sorry, C# is not my "native" programming language, but as far as I know, C# has almost the same reflection capabilities as Java. It should be easy to convert the code above to C# by looking at examples at MSDN:
https://msdn.microsoft.com/en-us/library/system.reflection.fieldinfo.getvalue(v=vs.110).aspx
for instance:
PropertyName.class.getField(fieldName) will become typeof(PropertyName).GetField(fieldName). And attributeField.get(PropertyName).toString() will probably become attribute.getValue(PropertyName). Check the MSDN article for the list of exceptions you need to handle while doing this.
By the way, you're right if you think that we created more code than we saved. Sometimes it's better to just leave things the way the are.
However, that is the solution for growing number of sub-ifs. You can easily put more fields to compare, but the nesting level won't change.
I would try to extract a new private method or local function for comparing fields by names.
Assuming your example was in Java, I would aim for something like this:
public void someBusinessLogicMethod() { // Define and intialize obj, objToFind, PropertyName // ... String[] fieldsToCompare = ["Name", "Role", "Value", "Class", "Top", "Left", "Height", "Width"]; if (this.compareGivenFields(obj, objToFind, PropertyName, fieldsToCompare)) { // Some code. } } private Boolean compareGivenFields(Object obj, Object objToFind, Object PropertyName, String[] fieldNames) { Boolean result = false; for (String fieldName : fieldNames) { result &= compareField(obj, objToFind, PropertyName, fieldName); } return result; } private Boolean compareField(Object obj, Object objToFind, Object PropertyName, String fieldName) { try { Field attributeField = PropertyName.class.getField(fieldName); try { String attribute = attributeField.get(PropertyName).toString(); return obj.Attributes[attribute].Equals(objToFind.Attributes[attribute]); } catch (IllegalAccessException e) { System.out.println("Error accessing field value."); } } catch(NoSuchFieldException e) { System.out.println("There's no such field."); } return false; }
In other languages which support direct field access by name (PHP, Javascript) solution might be even simpler.
Thanks for the idea, Miranda. I'll add it to my backlog.
Исправил, спасибо!
Hello Mahendra,
The main purpose of interfaces is to establish a "contract" between parts of your program—it's the way for client code to say "In this method I need any objects which can do this, this and that (described in interface). I don't really care about the class of that object, as long as it does what I need."
Let's see how this can be helpful using the analogy from real life:
You inherited a bar from your grandpa. There works a bartender named Joe. Some day Joe got drunk on the job and you decided to fire him. But there's a gotcha, only Joe knows how to handle the bar. You don't know how to replace him, because you don't know what potential candidate should be capable of doing.
So, your bar (client code) is coupled to the concrete class (Joe). In such case, you could only replace Joe with his son (subclass), who used to help Joe before and learned the ropes. But he's alcoholic too (inherited the behavior from Joe), so you have to think of something else.
Finally, you asked around and managed to write a job description for a bartender position (created the interface). And suddenly it seems that you can fill the position with anyone, who's capable of doing things listed in that document—be that experienced bartender or a part-time student.
Irony aside, here's how I decide whether or not I need an interface in particular situation:
- Would I need to replace this class in some client code with some other class in the future?
- Or do I have to provide some extension point for other people using this code, so that they could pass their own classes instead of default one?
If the answer is yes (for any of above), I create the interface and link the client code to the interface rather to a concrete class.
If the answer is no, I don't create interface and tie the code to a class. But even if in the future it turns out that I actually need some flexibility, I can use the Extract Interface refactoring to create a common interface.
Please note, that like any real life contract, interfaces create the burden of bureaucracy. Plus, the complexity: you create several entities (interface + class) instead of just one (a class). That's why I would not suggest creating interfaces for each class in the program.
Hope this makes sense!
Да, действительно, там была опечатка. Спасибо, исправил.
Hey Mahendra,
Nice question! Here's what I think:
1. You need a class anyway, since you have to put the extracted method body somewhere. You can not put it inside interface, right?
2. You can always extract interface from a resulting class later (see Extract Interface refactoring).
Добрый день.
Хороший вопрос, спасибо. Мне кажется, что новичку курс будет полезен, особенно секция с запахами плохого кода, т.к. обычно первый год в профессии люди только такой код и пишут.
Думаю, для себя это легче всего это понять полистав каталог рефакторинга, доступный на сайте. Если вы понимаете о чем там идёт речь, то я думаю, что курс будет вам полезен. В крайнем случае, вы всегда можете поросить возврат денег, если поймете, что материал для вас слишком сложный.
С уважением,
Александр Швец
Customer support service by UserEcho
As with all things in programming you have to balance performance cost with with any benefit gained. But I'd say if you're not running this code in a loop, don't worry about the performance.