I was thinking about object oriented design today, and I was wondering if you should avoid if statements. My thought is that in any case where you require an if statement you can simply create two objects that implement the same method. The two method implementations would simply be the two possible branches of the original if statement.
I realize that this seems extreme, but it seems as though you could try and argue it to some extent. Any thoughts on this?
EDIT
Wow that didn't take long. I suppose this is way too extreme. Is it possible to say though, that under OOP you should expect way less if statements?
SECOND EDIT
What about this: An object that determines its method implementation based on its attributes. That is to say you can implement someMethod() in two ways and specify some restrictions. At any point an object will route to the correct method implementation based on its properties. So in the case of if(x > 5) just have two methods that rely on the x attribute
I can tell you one thing. No matter what people say, thinking about simplifying and eliminating unnecessary branching is a sign of you maturing as a software developer. There are many reasons why branching is bad, testing, maintenance, higher rate of bugs and so on. This is one of the things I look for when interviewing people and is an excellent indicator how mature they are as a developer. I would encourage you to keep experimenting, simplifying your code and design by using less conditions. When I did this switch I found much less time debugging my code, it simply worked, then when I had to change something, changes were super easy to make since most of the code was sequential. Again I would encourage you 100% to keep doing what you are doing no matter what other people say. Keep in mind most developers are working and thinking at much lower level and just follow the rules. So good job bringing this up.
Explain how to implement the following without an if statement or ternary logic:
if ( x < 5 ) {
x = 0
} else {
print x;
}
Yes its true that often complex conditionals can be simplified with polymorphishm. But its not useful all the time. Go read Fowler's Refactoring book to get an idea of when.
http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
Completely eliminating if statements is not realistic and I don't think that is what Ori is suggesting. But they can often be replaced using polymorphism. (And so can many switch statements).
Francesco Cirillo started the Anti-If Campaign to raise awareness of this issue. He says:
Knowing how to use objects lets developers eliminate IFs based on type, those that most often compromise software's flexibility and ability to evolve.
You or your team can also join the campaign.
One of my teacher used to say that. I tend to think that people being so dogmatic about that kind of thing usually don't program for a living.
Avoiding If Statement: There are many ways to do, one of them is below:
int i=0;
if(i==1)
{
//Statement1
}
if(i==2)
{
//Statement2
}
if(i==3)
{
//Statement3
}
if(i==4)
{
//Statement4
}
Using Dictionary and delegate:
delegate void GetStatement ();
Dictionary<int,GetStatement > valuesDic=new Dictionary<int,GetStatement >();
void GetStatement1()
{
//Statement1
}
void GetStatement2()
{
//Statement2
}
void GetStatement3()
{
//Statement3
}
void GetStatement4()
{
//Statement4
}
void LoadValues()
{
valuesDic.Add(1,GetStatement1);
valuesDic.Add(2,GetStatement2);
valuesDic.Add(3,GetStatement3);
valuesDic.Add(4,GetStatement4);
}
Replacing If Statement:
int i=0;
valuesDic[i].Invoke();
Have a look at the Anti-If Campaign The idea is not to replace every single if in your application with the Strategy or State Pattern. The idea is that when you have complex branching logic especially based on something like an enumeration, you should look to refactoring to the Strategy Pattern.
And that case you can remove the if all together by using a Factory. Here is a relatively straightforward example. Of course as I said in a real case, the logic in your strategies would be a bit more complex than just printing out "I'm Active".
public enum WorkflowState
{
Ready,
Active,
Complete
}
public interface IWorkflowStrategy
{
void Execute();
}
public class ActiveWorkflowStrategy:IWorkflowStrategy
{
public void Execute()
{
Console.WriteLine("The Workflow is Active");
}
}
public class ReadyWorkflowStrategy:IWorkflowStrategy
{
public void Execute()
{
Console.WriteLine("The Workflow is Ready");
}
}
public class CompleteWorkflowStrategy:IWorkflowStrategy
{
public void Execute()
{
Console.WriteLine("The Workflow is Complete");
}
}
public class WorkflowStrategyFactory
{
private static Dictionary<WorkflowState, IWorkflowStrategy> _Strategies=
new Dictionary<WorkflowState, IWorkflowStrategy>();
public WorkflowStrategyFactory()
{
_Strategies[WorkflowState.Ready]=new ReadyWorkflowStrategy();
_Strategies[WorkflowState.Active]= new ActiveWorkflowStrategy();
_Strategies[WorkflowState.Complete] = new CompleteWorkflowStrategy();
}
public IWorkflowStrategy GetStrategy(WorkflowState state)
{
return _Strategies[state];
}
}
public class Workflow
{
public Workflow(WorkflowState state)
{
CurrentState = state;
}
public WorkflowState CurrentState { get; set; }
}
public class WorkflowEngine
{
static void Main(string[] args)
{
var factory = new WorkflowStrategyFactory();
var workflows =
new List<Workflow>
{
new Workflow(WorkflowState.Active),
new Workflow(WorkflowState.Complete),
new Workflow(WorkflowState.Ready)
};
foreach (var workflow in workflows)
{
factory.GetStrategy(workflow.CurrentState).
Execute();
}
}
}
In some ways this can be a good idea. Swiching on a type field inside an object is usually a bad idea when you can use virtual functtions instead. But the virtual function mechanism is in no way intended to replace the if() test in general.
How do you decide which object's method to use without an if statement?
It depends on what the original statement is comparing. My rule of thumb is that if it's a switch or if testing equality against an enumeration, then that's a good candidate for a separate method. However, switch and if statements are used for many, many other kinds of tests -- there's no good way to replace the relational operators (<, >, <=, >=) with specialized methods, and some kinds of enumerated tests work much better with standard statements.
So you should only replace ifs if they look like this:
if (obj.Name == "foo" || obj.Name == "bar") { obj.DoSomething(); }
else if (obj.Name == "baz") { obj.DoSomethingElse(); }
else { obj.DoDefault(); }
In answer to ifTrue's question:
Well, if you have open classes and a sufficiently strong dependent type system, it's easy, if a bit silly. Informally and in no particular language:
class Nat {
def cond = {
print this;
return this;
}
}
class NatLessThan<5:Nat> { // subclass of Nat
override cond = {
return 0;
}
}
x = x.cond();
(continued...)
Or, with no open classes but assuming multiple dispatch and anonymous classes:
class MyCondFunctor {
function branch(Nat n) {
print n;
return n;
}
function branch(n:NatLessThan<5:Nat>) {
return 0;
}
}
x = new MyCondFunctor.branch(x);
Or, as before but with anonymous classes:
x = new {
function branch(Nat n) {
print n;
return n;
}
function branch(n:NatLessThan<5:Nat>) {
return 0;
}
}.branch(x);
You'd have a much easier time if you refactored that logic, of course. Remember that there exist fully Turing-complete type systems.
Assume we have conditional values.
public void testMe(int i){
if(i=1){
somevalue=value1;
}
if(i=2){
somevalue=value2;
}
if(i=3){
somevalue=value3;
}
}
//**$$$$$you can replace the boring IF blocks with Map.$$$$$**
// ============================================================
Same method would look like this:
--------------------------------
public void testMe(int i){
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1,value1);
map.put(2,value2);
map.put(3,value3);
}
This will avoid the complicated if conditions.
You can use simliar solution when using factory patterns for loading classes.
public void loadAnimalsKingdom(String animalKingdomType)
if(animalKingdomType="bird"){
Bird b = new Bird();
}
if(animalKingdomType="animal"){
Animal a= new Animal();
}
if(animalKingdomType="reptile"){
Reptile r= new Reptile();
}
}
Now using map :
public void loadAnimalsKingdom(String animalKingdomType)
{
Map <String,String> map = new HashMap<String,String>();
map.put("bird","com.animalworld.Bird.Class");
map.put("animal","com.animalworld.Animal.Class");
map.put("reptile","com.animalworld.Reptile.Class");
map.get(animalKingdomType);
***Use class loader to load the classes on demand once you extract the required class from the map.***
}
Like the solution? Give thumbs-up. - Vv
Creating a whole new class for an else, while technically doable, would likely result in code that is hard to read, maintain, or even prove correct.
That's an interesting idea. I think that you could theoretically do this, but it would be an enormous pain in a language not specifically designed to support it. I certainly don't see any reason to.
I think what he is saying or what he means to say is that he thinks it is best to avoid over-abuse of "tagging" and adding custom functionality to a class by several if statements when it better makes sense to subclass or rethink the object hierarchy.
It is quite extreme. Doing what you are suggesting would cause a lot of needless code duplication, unless the entire function was completely different, based on a single surrounding if; and if so, that if should probably have been on the other side of the method invocation.
If-statements certainly have their place in object-orient design.
Surely some form of comparison needs to be made regardless of what you do? In the end ... sure you can avoid if statements but you'd be producing code that is IDENTICAL to the code using an if statement.
Someone correct me if im wrong but I can't think of a time where you could get any win form doing this.
I think applying that argument to the idea of every if statement is pretty extreme, but some languages give you the ability to apply that idea in certain scenarios.
Here's a sample Python implementation I wrote in the past for a fixed-sized deque (double-ended queue). Instead of creating a "remove" method and having if statements inside it to see if the list is full or not, you just create two methods and reassign them to the "remove" function as needed.
The following example only lists the "remove" method, but obviously there are "append" methods and the like also.
class StaticDeque(collections.deque):
def __init__(self, maxSize):
collections.deque.__init__(self)
self._maxSize = int(maxSize)
self._setNotFull()
def _setFull(self):
self._full = True
self.remove = self._full_remove
def _setNotFull(self):
self._full = False
self.remove = self._not_full_remove
def _not_full_remove(self,value):
collections.deque.remove(self,value)
def _full_remove(self,value):
collections.deque.remove(self,value)
if len(self) != self._maxSize and self._full:
self._setNotFull()
In most cases it's not that useful of an idea, but sometimes it can be helpful.
I will say the answer is vaguely yes-ish. Especially when the language allows some heavy duty functional programming (ie C#, F#, OCaml).
A component that contains 2 if statements strongly couples two business rules so break it up.
Take that as a very general rule of thumb but I would agree. If you have a bunch of if statements, maybe you should think about another approach.
If-statements are pretty core to programming so, in short, you cannot sensibly avoid them.
However, a key goal in OOP--in fact, one of the "pillars"--is encapsulation. The old "encapsulate what varies" rule helps you remove those troublesome if and case statements where you are trying to account for every option in your object. A better solution to dealing with branches, special cases, etc. is to use something like the "Factory" design pattern (Abstract Factory or Factory Method--depending on needs, of course).
For example, rather than having your main code loop check which OS your using with if statements then branch to create GUI windows with different options for each OS, your main code would create an object from the factory, which use the OS to determine which OS-specific concrete object to make. In doing this you are taking the variations (and the long if-then-else clauses) out of your main code loop and letting the child objects handle it--so the next time you need to make a change such as supporting a new OS, you merely add a new class from the factory interface.
I've been following the anti-if talk lately and it does sound like extreme / hyperbolic rhetoric to me. However I think there is truth in this statement: often the logic of an if statement can be more appropriately implemented via polymorphism. I think it is good to keep that in mind every time you right an if statement. That being said, I think the if statement is still a core logic structure, and it should not be feared or avoided as a tenet.
My two bits here of what I understand of the Object Oriented approach -
First, what objects in a program should be intuitive. That is, I should not try to create a 'Arithmatic' class to provide mathematical functions. This is an abuse of OOD.
Second and this is a very strong opinion of mine. It should not be called Object Oriented design but Object and Method Oriented design! If the method names of the objects are themselves not intuitive then inherited objects might end up reimplementing the methods already available.
Object Oriented approach, according to me, is not a replacement for the Procedural approach. Rather it is mainly for two main reasons for the creators of the language -
Better capability of scoping of variables.
Better capability of garbage collection rather than having too many global variables.
I agree with Vance that the IF is not good, because it increases the conditional complexity and should be avoided as possible.
Polymorphism is a totally viable solution at condition it's used to make sense and not to "Avoid If".
A side note that does not fit to your OOP requirements but the Data Oriented approach also tends to avoid the branching.
You must understand what (x > 5) really mean. Assuming that x represents a number, then it basically "classifies" all numbers greater than five. So the code would look like this in a language with python syntax:
class Number(Object):
# ... Number implementation code ... #
def doSomething():
self = 0
return self
def doSomethingElse():
pass
class GreaterThan5(Number):
def doSomething():
print "I am " + self
def doSomethingElse():
print "I like turtles!"
Then we could run code like the following:
>>> type(3)
<class Number>
>>> type(3+3)
<class GreaterThan5>
>>> 3.doSomething()
0
>>> (3 + 3).doSomething()
I am 6
>>> (7 - 3).doSomethingElse()
>>>
The automatic type conversion here is important. As far as I am aware, none of the languages today allow you to mess with integers this much.
In the end, you can do in your code whatever. As long as the people reading it can understand immediately. So the polymorphic dispatch on integers or anything unordinary must have really good reasoning behind it.
Related
I was reading through strategy pattern and was trying to implement it but I have got stuck at deciding the strategy implementation which I feel violates the open-closed principle.
In strategy pattern we code to interface and based on client interaction we will pass in the strategy implementation.
Now if we have bunch of strategies so we need to decide using conditions which strategy the client chooses something like
IStrategy str;
if(stragety1) {
str = new Strategy1()
} else if (stragety2) {
str = new Strategy2()
} and so on..
str.run()
Now as per open-closed principle the above is open to extension but it is not closed to modification
If I need to add another strategy(extension) in future I do need to alter this code.
is there a way where this could be avoided or it is how we need to implement strategy pattern ?
1) You must separate selecting/creating a concrete strategy from its uses. I. e. use function selectStrategy, pass it as (constructor) parameter, etc.
2) There is no way to fully avoid conditional creation, but you can hide it (e. g. using some dictionary for mapping state=>strategy) and/or shift it into another level of the application. The last approach is very powerful and flexible, but depends on the task. In some cases you may put selecting/creating on the same level that uses it. In other cases you may even end up with delegation selecting/creating to the highest/lowest level.
2.1) You can use the Registry pattern and kinda avoid modification of "core" object when adding new strategy's.
This is indeed not closed to modification, but that is due to the way you initialize. You are using a value (enum?) to determine which Strategy subclass should be used. As #bpjoshi points out their comment, this is more of a Factory pattern.
Wikipedia discusses how a Strategy pattern can support the Open/Closed Principle, instead of hampering it.
In that example, they use a Car class with a Brake Strategy. Some cars brake with ABS, some don't. Different Car subclasses and instances can be given different Strategies for braking.
To get your code closed for modification, you need to select the Strategies differently. You want to select the Strategy in the place where new behavior or subclass is defined. You'd have to refactor your code so that the specific Strategy subclass is applied at the point where the code is extended.
I think, there is misunderstanding about Closed for Modifications.
In 1988, Mayer said:
Software that works should when possible not be changed when your application is extended with new functionality.
and Rober C. Matrin said:
This definition is obviously dated.
Think about that very carefully. If the behaviors of all the modules in your system could be extended, without modifying them, then you could add new features to that system without modifying any old code. The features would be added solely by writing new code.
https://8thlight.com/blog/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html
Adding some new codes without modifying old codes do not conflict with Open-Closed Principle.
I think the decision you are referring to should be the responsibility of a factory class. The following is some example code:
public interface ISalary
{
decimal Calculate();
}
public class ManagerSalary : ISalary
{
public decimal Calculate()
{
return 0;
}
}
public class AdminSalary : ISalary
{
public decimal Calculate()
{
return 0;
}
}
public class Employee
{
private ISalary salary;
public Employee(ISalary salary)
{
this.salary = salary;
}
public string Name { get; set; }
public decimal CalculateSalary()
{
return this.salary.Calculate();
}
}
The Employee class uses the Strategy pattern and follows the Open/Closed principle, i.e. it is open to new strategy types (ISalary implementations) through injection via the constructor, but closed to modification.
The piece that is missing is the code that creates the Employee objects, something like:
public enum EmployeeType
{
Manager,
Admin
}
public class EmployeeFactory
{
public Employee CreateEmployee(EmployeeType type)
{
if (type == EmployeeType.Manager)
return new Employee(new ManagerSalary());
else if (type == EmployeeType.Admin)
return new Employee(new AdminSalary());
etc
}
}
This is a very simple factory pattern. There are better ways to do this but this is the simplest way to explain the concept.
Before Java 8, we implemented Comparable.compareTo(...) like this:
public int compare(Person a, Person b) {
return new CompareToBuilder()
.append(a.getLastName(), b.getLastName())
.append(a.getFirstName(), b.getFirstName())
.toComparison();
}
As of Java 8, we can do it like this:
public int compare(Person a, Person b) {
return Comparator
.comparing(Person::getLastName)
.thenComparing(Person::getFirstName)
.compare(a, b);
}
The new Java 8 way might allow us to drop the commons-lang3 dependency. Is that new Java 8 way faster? Is there a way to automatically migrate? I didn't find an IntelliJ intention for it.
Notice that it becomes a bit more complex when there are reverse orders and non natural comparison is involved:
public int compare(SingleBenchmarkResult a, SingleBenchmarkResult b) {
return new CompareToBuilder()
.append(b.hasAnyFailure(), a.hasAnyFailure()) // Reverse
.append(a.getAverageScore(), b.getAverageScore(), resilientScoreComparator)
.toComparison();
}
becomes
public int compare(SingleBenchmarkResult a, SingleBenchmarkResult b) {
return Comparator
.comparing(SingleBenchmarkResult::hasAnyFailure, Comparator.reverseOrder()) // Reverse
.thenComparing(SingleBenchmarkResult::getAverageScore, resilientScoreComparator)
.compare(a, b);
}
If you write it this way
public int compare(Person a, Person b) {
return Comparator
.comparing(Person::getLastName)
.thenComparing(Person::getFirstName)
.compare(a, b);
}
you are wasting performance by constructing a new Comparator for each comparison. And it should be obviously nonsensical when looking at the surrounding code. The compare(Person a, Person b) method surely is part of a class implementing Comparator<Person>, which you instantiate at some place to get the desired comparator. You should replace that instance by a sole Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName) instance instead, used throughout the entire operation.
E.g.
// reusable
static final Comparator<Person> By_NAME = Comparator
.comparing(Person::getLastName).thenComparing(Person::getFirstName);
or ad hoc
listOfPersons.sort(Comparator.comparing(Person::getLastName)
.thenComparing(Person::getFirstName));
If you use it that way, it’s very likely to be faster. However, you should see, that there is no simple pattern-based replacement possible. You have to replace the use sites of the class with that simple declarative construct and make a decision whether to use a shared comparator instance for multiple use sites or create it ad-hoc. Then, you can remove the entire old implementation class or at least, remove the comparator functionality from it if it still serves other purposes.
I don't think there is any pre-defined inspection for that. You might try to use IntelliJ's structural-search, although I think it might by quite tricky to do that for every possible case. One possibility for a simple case with two comparisons might be the following:
search template (occurence count of $TYPE$ and $z$ is 2):
$ReturnType$ $MethodName$($TYPE$ $z$) {
return new CompareToBuilder()
.append($A$.$m$(), $B$.$m$())
.append($A$.$m1$(), $B$.$m1$())
.toComparison();
}
replacement template:
$ReturnType$ $MethodName$($TYPE$ $z$) {
return java.util.Comparator
.comparing($TYPE$::$m$)
.thenComparing($TYPE$::$m1$)
.compare($A$, $B$);
}
I am not an expert on structural search, but I guess you would have to make another pattern for calls with more or less comparisons.
Although I'm not sure if I've chosen the right name for it, anyone who's worked on a large project with lots of features has probably seen it: some boolean return function gets bloated with the interaction of every little feature. Eventually what was once a simple one or two variable check becomes:
public boolean showFavoritesTool(UserData userData){
if(currentPage.isPremiumPage())
{
return true;
}
if(!userData.isLoggedIn())
{
return false;
}
if(userData.isMember())
{
return userData.getPreferences().isFavoritesTurnedOn();
}
if(getUrlParams()["showFavorites"])
{
return getUrlParams()["showFavorites"]
}
return false;
}
Edit: Let me clarify, this is just an early example of functions like this. At some point, it would grow as new features are developed to at least twice this size. The function I was looking at that prompted this question had at least 15 variables, some of which were nested. This code may look simple, but it won't remain so as new variables are added.
Everytime a new feature is added, another entry is thrown into the flag function. They don't usually overlap, but when they do you can be sure that no one has thought about what should happen. It doesn't take long before these functions become hard to interpret.
Is there a cleaner solution to this? Also, if that cleaner solution involves more architecture, when would one implement it? As soon as a second variable is added? Or is there some breaking point?
Your question is rather general and it is difficult to understand its scope, nevertheless I will try and provide some insight which will hopefully answer it.
Everytime a new feature is added, another entry is thrown into the flag function. They don't usually overlap, but when they do you can be sure that no one has thought about what should happen
This is a nasty side effect of poor planning and design. Code should be closed for modification, but open to extension
Design with the future in mind, as mentioned previously by Yuval Itzchakov, an interface which contains an abstract showFavouritesTool() method which is overriden by each user class depending on each classes requirements will provide greater flexibility, and adhere to the Open/Closed principle. Unfortunately, with the limited information given, it would be difficult to create an example which fits your problem.
Incidently, there will be occassions where multiple boolean expressions need checking. Why not simplify the method by using one concise statement.
For example:
public boolean showFavoritesTool(UserData userData){
return currentPage.isPremiumPage()
|| userData.isLoggedIn() && userData.isMember() && userData.getPreferences().isFavoritesTurnedOn()
|| userData.isLoggedIn() && getUrlParams()["showFavorites"];
}
I would just rewrite it in a more conscious and understandable form. This requires some care because early returns, (double) negations and the like often obscure the behavior and it is easy to introduce bugs.
public boolean showFavoritesTool(UserData userData)
{
return currentPage.isPremiumPage()
|| userData.isLoggedIn() && userData.isMember() && userData.getPreferences().isFavoritesTurnedOn()
|| userData.isLoggedIn() && getUrlParams()["showFavorites"];
}
If the logic becomes is really complex it helps introducing some intermediate variables.
public boolean showFavoritesTool(UserData userData)
{
var isPremiumPage = currentPage.isPremiumPage();
var isLoggedIn = userData.isLoggedIn();
var isMemberAndHasFavoritesTurnedOn = userData.isMember() && userData.getPreferences().isFavoritesTurnedOn();
var urlIndicatesShowFavorites = getUrlParams()["showFavorites"];
return isPremiumPage
|| isLoggedIn && isMemberAndHasFavoritesTurnedOn
|| isLoggedIn && urlIndicatesShowFavorites;
}
In this example it is a bit to much but you get the idea. It is usually a good idea to align the meaning of intermediate variables with business or technical requirements.
If all the validations stay in the same place, are clear (for example, take the ! out of the second if and make it a return true, put the return value in the third if and make it a return true also, same with the last if) and commented when "favorites tool" should be shown, I don't see a problem with it.
I think your question is a bit too general, since i don't fully understand the scope of the problem. there are multiple uses of fields which we have no knowledge about.
But in general, if you are trying to categories which set of features you want to expose to a group of users, you could make them all inherit a base type, which has an abstract method with a function called SetFavoriteTool, like so:
public abstract class BaseData
{
public abstract bool ShowFavoriteTool();
}
public class UserData : BaseData
{
public override bool ShowFavoriteTool()
{
if ....
}
}
or if you're more into interfaces, you could depend on an IFavoriteTool:
public interface IFavoriteTool
{
bool ShowFavoriteTool();
}
public class UserData : IFavoriteTool
{
public bool ShowFavoriteTool()
{
if..
}
}
and then you could change your method to:
public bool ShowFavoriteTool(UserData userData)
{
var favoriteTool = (IFavoriteTool) userData;
return favoriteTool.ShowFavoriteTool();
}
This is just a lead since i don't really understand the Domain problem you're dealing with.
Hope this helps.
This is what's known as "code rot." It's a process of source degrading in performance and/or maintainability. Eventually it may degrade to a point where the performance gets so bad or it becomes so unmaintainable that you have to start over (version 2.0)
Code rod occurs as a result of incremental enhancements or bug fixes that causes your design veer further and further away from the original design.
To combat code rot, you need to have (and enforce) good standards. Have code reviews, code audits, document source, write unit tests, etc.
I will occasionally create my own enum to declare the state of the object. In this case, something similar to this:
public enum FavoriteToolState {
IsVisible,
IsHidden
}
This way, you could set the state of the favorite inside the inner methods which actually determine whether or not the favorite is premium, or whether the user has logged in, or any of those other options, and instead of checking each of those methods, you could check to see if the current FavoriteToolState is FavoriteToolState.IsVisible.
Whether or not this is cleaner could be argued either way, I suppose. I prefer this way in some cases.
I have a habit of creating classes that tend to pass objects around to perform operations on them rather than assigning them to a member variable and having operations refer to the member variable. It feels much more procedural to me than OO.
Is this a terrible practice? If so, what are the adverse effects (performance, memory consumption, more error-prone)? Is it simply easier and more closely aligned to OO principles like encapsulation to favour member variables?
A contrived example of what I mean is below. I tend to do the following;
public class MyObj()
{
public MyObj() {}
public void DoVariousThings(OtherObj oo)
{
if (Validate(oo))
{
Save(oo);
}
}
private bool Validate(OtherObj oo)
{
// Do stuff related to validation
}
private bool Save(OtherObj oo)
{
// Do stuff related to saving
}
}
whereas I suspect I should be doing the following;
public class MyObj()
{
private OtherObj _oo;
public MyObj(OtherObj oo)
{
_oo = oo;
}
public void DoVariousThings()
{
if (Validate())
{
Save();
}
}
private bool Validate()
{
// Do stuff related to validation with _oo
}
private bool Save()
{
// Do stuff related to saving with _oo
}
}
If you write your programs in an object oriented language, people will expect object oriented code. As such, in your first example, they would probably expect that the reason for making oo a parameter is that you will use different objects for it all the time. In your second example, they would know that you always use the same instance (as initialized in the constructor).
Now, if you use the same object all the time, but still write your code like in your first example, you will have them thoroughly confused. When an interface is well designed, it should be obvious how to use it. This is not the case in your first example.
I think you already answered your question yourself, you seem to be aware of the fact that the 2nd approach is more favorable in general and should be used (unless there are serious reasons for the first approach).
Advantages that come to my mind immediately:
Simplified readability and maintainability, both for you and for others
Only one entry point, therefore only needing to checking for != null etc.
In case you want to put that class under test, it's way easier, i.e., getting something like this (extracting interface IOtherObj from OtherObj and working with that):
public MyObj (IOtherObj oo)
{
if (oo == null) throw...
_oo = oo;
}
Talking of the adverse effects of your way, there are none, but only if you are keeping the programs and the code to yourself,, what are you doing is NOT a standard thing, say, if after some time, you start to work making libraries and code that may be used by others also, then it is a big problem. The may pass any foo object and hope that it would work.
you have to validate the object before passing it and if the validation fails do things accordingly, but if u use the standard OOP way, there is no need for validation or taking up the cases where an inappropriate type object is pass,
In a nutshell, your way is bad for :
1. code re-usability.
2. you have to handle more exceptions.
3. okay, if u r keeping things to urself, otherwise, not a good practice.
hope, it cleared some doubt.
Today I read a book and the author wrote that in a well-designed class the only way to access attributes is through one of that class methods. Is it a widely accepted thought? Why is it so important to encapsulate the attributes? What could be the consequences of not doing it? I read somewhere earlier that this improves security or something like that. Any example in PHP or Java would be very helpful.
Is it a widely accepted thought?
In the object-oriented world, yes.
Why is it so important to encapsulate the attributes? What could be the consequences of not doing it?
Objects are intended to be cohesive entities containing data and behavior that other objects can access in a controlled way through a public interface. If an class does not encapsulate its data and behavior, it no longer has control over the data being accessed and cannot fulfill its contracts with other objects implied by the public interface.
One of the big problems with this is that if a class has to change internally, the public interface shouldn't have to change. That way it doesn't break any code and other classes can continue using it as before.
Any example in PHP or Java would be very helpful.
Here's a Java example:
public class MyClass {
// Should not be < 0
public int importantValue;
...
public void setImportantValue(int newValue) {
if (newValue < 0) {
throw new IllegalArgumentException("value cannot be < 0");
}
}
...
}
The problem here is that because I haven't encapsulated importantValue by making it private rather than public, anyone can come along and circumvent the check I put in the setter to prevent the object from having an invalid state. importantValue should never be less than 0, but the lack of encapsulation makes it impossible to prevent it from being so.
What could be the consequences of not
doing it?
The whole idea behind encapsulation is that all knowledge of anything related to the class (other than its interface) is within the class itself. For example, allowing direct access to attributes puts the onus of making sure any assignments are valid on the code doing the assigning. If the definition of what's valid changes, you have to go through and audit everything using the class to make sure they conform. Encapsulating the rule in a "setter" method means you only have to change it in one place, and any caller trying anything funny can get an exception thrown at it in return. There are lots of other things you might want to do when an attribute changes, and a setter is the place to do it.
Whether or not allowing direct access for attributes that don't have any rules to bind them (e.g., anything that fits in an integer is okay) is good practice is debatable. I suppose that using getters and setters is a good idea for the sake of consistency, i.e., you always know that you can call setFoo() to alter the foo attribute without having to look up whether or not you can do it directly. They also allow you to future-proof your class so that if you have additional code to execute, the place to put it is already there.
Personally, I think having to use getters and setters is clumsy-looking. I'd much rather write x.foo = 34 than x.setFoo(34) and look forward to the day when some language comes up with the equivalent of database triggers for members that allow you to define code that fires before, after or instead of a assignments.
Opinions on how "good OOD" is achieved are dime a dozen, and also very experienced programmers and designers tend to disagree about design choices and philosophies. This could be a flame-war starter, if you ask people across a wide varieties of language background and paradigms.
And yes, in theory are theory and practice the same, so language choice shouldn't influence high level design very much. But in practice they do, and good and bad things happen because of that.
Let me add this:
It depends. Encapsulation (in a supporting language) gives you some control over how you classes are used, so you can tell people: this is the API, and you have to use this. In other languages (e.g. python) the difference between official API and informal (subject to change) interfaces is by naming convention only (after all, we're all consenting adults here)
Encapsulation is not a security feature.
Another thought to ponder
Encapsulation with accessors also provides much better maintainability in the future. In Feanor's answer above, it works great to enforce security checks (assuming your instvar is private), but it can have much further reaching benifits.
Consider the following scenario:
1) you complete your application, and distribute it to some set of users (internal, external, whatever).
2) BigCustomerA approaches your team and wants an audit trail added to the product.
If everyone is using the accessor methods in their code, this becomes almost trivial to implement. Something like so:
MyAPI Version 1.0
public class MyClass {
private int importantValue;
...
public void setImportantValue(int newValue) {
if (newValue < 0) {
throw new IllegalArgumentException("value cannot be < 0");
}
importantValue = newValue;
}
...
}
MyAPI V1.1 (now with audit trails)
public class MyClass {
private int importantValue;
...
public void setImportantValue(int newValue) {
if (newValue < 0) {
throw new IllegalArgumentException("value cannot be < 0");
}
this.addAuditTrail("importantValue", importantValue, newValue);
importantValue = newValue;
}
...
}
Existing users of the API make no changes to their code and the new feature (audit trail) is now available.
Without encapsulation using accessors your faced with a huge migration effort.
When coding for the first time, it will seem like a lot of work. Its much faster to type: class.varName = something vs class.setVarName(something); but if everyone took the easy way out, getting paid for BigCustomerA's feature request would be a huge effort.
In Object Oriente Programming there is a principle that is known as (http://en.wikipedia.org/wiki/Open/closed_principle):
POC --> Principle of Open and Closed. This principle stays for: a well class design should be opened for extensibility (inheritance) but closed for modification of internal members (encapsulation). It means that you could not be able to modify the state of an object without taking care about it.
So, new languages only modify internal variables (fields) through properties (getters and setters methods in C++ or Java). In C# properties compile to methods in MSIL.
C#:
int _myproperty = 0;
public int MyProperty
{
get { return _myproperty; }
set { if (_someVarieble = someConstantValue) { _myproperty = value; } else { _myproperty = _someOtherValue; } }
}
C++/Java:
int _myproperty = 0;
public void setMyProperty(int value)
{
if (value = someConstantValue) { _myproperty = value; } else { _myproperty = _someOtherValue; }
}
public int getMyProperty()
{
return _myproperty;
}
Take theses ideas (from Head First C#):
Think about ways the fields can misused. What can go wrong if they're not set properly.
Is everything in your class public? Spend some time thinking about encapsulation.
What fields require processing or calculation? They are prime candidates.
Only make fields and methods public if you need to. If you don't have a reason to declare something public, don't.