Look at this method; this is a contrived example, but think of something like a 2D game - this checks if two game entities have collided (passed through each other) and produces a result that describes the collision and how to resolve it (how to reposition the two entities). In reality, this would probably need to take in additional parameters, but let's keep it relatively simple.
Look at this method; this is a contrived example, but think of something like a 2D game - this checks if two game entities have collided (passed through each other) and produces a result that describes the collision and how to resolve it (how to reposition the two entities). In reality, this would probably need to take in additional parameters, but let's keep it relatively simple.
Well, let's create a class to represent an axis-aligned bounding rectangle, let's give it an IntersectIntersect method, and let's put that wall of code in there. Now
This may require some cleanup, because the different parts of the code probably depend on each other in subtle ways (variables may be reused, one part of the code may make assumptions about the previous section, etc.)
But after the separation, I can be a bit more declarative - I just want to tell the code to compute the intersection; I don't care how:
// The method is now essentially self-documenting; that // that documentation comment formfrom before is now redundant CollisionInfo ResolveColision(BoundingRect rect1, BoundingRect rect2) { BoundingRect intersection = rect1.Intersect(rect2); // Use 'intersection' to figure out how to resolve the collision // (... omitted ...) return new CollisionInfo(/* ... omitted ... */); } // Sometimes, you may choose to keep the original method as an // overload, for convenience, or for backward compatibility. // But this just delegates to the previous method, so it's not a // problem in terms of readability, maintenance, etc. CollisionInfo ResolveColision( double left1, double top1, double right1, double bottom1, double left2, double top2, double right2, double bottom2) { return ResolveCollision( new BoundingRectangle(left1, top1, right1, bottom1) new BoundingRectangle(left2, top2, right2, bottom2)); } Besides, now I can reuse the BoundingRect class, and its Intersect method, elsewhere, and I can change the implementation of Intersect without affecting the code that calls it.
Well, let's create a class to represent an axis-aligned bounding rectangle, let's give it an Intersect method, and let's put that wall of code in there. Now I can be a bit more declarative - I just want to tell the code to compute the intersection; I don't care how:
// The method is now essentially self-documenting; that // documentation comment form before is now redundant CollisionInfo ResolveColision(BoundingRect rect1, BoundingRect rect2) { BoundingRect intersection = rect1.Intersect(rect2); // Use 'intersection' to figure out how to resolve the collision // (... omitted ...) return new CollisionInfo(/* ... omitted ... */); } // Sometimes, you may choose to keep the original method as an // overload, for convenience, or for backward compatibility. // But this just delegates to the previous method, so it's not a // problem in terms of readability, maintenance, etc. CollisionInfo ResolveColision( double left1, double top1, double right1, double bottom1, double left2, double top2, double right2, double bottom2) { return ResolveCollision( new BoundingRectangle(left1, top1, right1, bottom1) new BoundingRectangle(left2, top2, right2, bottom2)); } Well, let's create a class to represent an axis-aligned bounding rectangle, let's give it an Intersect method, and let's put that wall of code in there.
This may require some cleanup, because the different parts of the code probably depend on each other in subtle ways (variables may be reused, one part of the code may make assumptions about the previous section, etc.)
But after the separation, I can be a bit more declarative - I just want to tell the code to compute the intersection; I don't care how:
// The method is now essentially self-documenting; // that documentation comment from before is now redundant CollisionInfo ResolveColision(BoundingRect rect1, BoundingRect rect2) { BoundingRect intersection = rect1.Intersect(rect2); // Use 'intersection' to figure out how to resolve the collision // (... omitted ...) return new CollisionInfo(/* ... omitted ... */); } // Sometimes, you may choose to keep the original method as an // overload, for convenience, or for backward compatibility. // But this just delegates to the previous method, so it's not a // problem in terms of readability, maintenance, etc. CollisionInfo ResolveColision( double left1, double top1, double right1, double bottom1, double left2, double top2, double right2, double bottom2) { return ResolveCollision( new BoundingRectangle(left1, top1, right1, bottom1) new BoundingRectangle(left2, top2, right2, bottom2)); } Besides, now I can reuse the BoundingRect class, and its Intersect method, elsewhere, and I can change the implementation of Intersect without affecting the code that calls it.
E.g., inside the method, there's probably going to be a code block that only uses a couple of parameters with a comment on top of it explaining what it does. Or maybe there will be a block comprised of one or more if-conditionals. And the details of that block are not going to be the main point of the method. You can probably do the Extract Method refactoring and get a cleaner, easier to understand code in the original method - code that more succinctly expresses what the method actually does. But then you should ask yourself, does thatthe newly extracted method really belong to the same class? Maybe it does, but maybe it would be better to relocate it.
E.g., inside the method, there's probably going to be a code block that only uses a couple of parameters with a comment on top of it explaining what it does. Or maybe there will be a block comprised of one or more if-conditionals. And the details of that block are not going to be the main point of the method. You can probably do the Extract Method refactoring and get a cleaner, easier to understand code in the original method - code that more succinctly expresses what the method actually does. But then you should ask yourself, does that method really belong to the same class? Maybe it does, but maybe it would be better to relocate it.
E.g., inside the method, there's probably going to be a code block that only uses a couple of parameters with a comment on top of it explaining what it does. Or maybe there will be a block comprised of one or more if-conditionals. And the details of that block are not going to be the main point of the method. You can probably do the Extract Method refactoring and get a cleaner, easier to understand code in the original method - code that more succinctly expresses what the method actually does. But then you should ask yourself, does the newly extracted method really belong to the same class? Maybe it does, but maybe it would be better to relocate it.