I just finished creating my first major application in C#/Silverlight. In the end the total line count came out to over 12,000 lines of code. Considering this was a rewrite of a php/javascript application I created 2 years that was over 28,000 lines I am actually quite proud of my accomplishment.
After reading many questions and answers here on stackoverflow and other sites online, I followed many posters advice: I created classes, procedures, and such for things that I would have a year ago copied and pasted; I created logic charts to figure out complex functions; making sure there are no crazy hidden characters (used tabs instead of spaces); and a few others things; place comments where necessary (I have lots of comments).
My application consists of 4 tiles laid out horizontally that have user controls loaded into each slice. You can have between one and four slices loaded at anytime. If you have once slice loaded, the slice takes up the entire artboard...if you have 2 loaded, each take up half, 3 a third, 4 a quarter.
Each one of these slices represent (for the sake of this example) a light control. Each slice has 3 slider controls in it. Now when I coded the functionality of the sliders, I used a switch/case statement inside of a public function that would run the command on the specified slice/slider. This made for some d开发者_如何学Cuplicate code but I saw no way around it as each slice was named differently. So I would do slice1.my.commands(); slice2.my.commands(); etc.
My question to you is how do I clean up my code even futher? (Sadly I cannot post any of my code). Is there any way to take this repetion out of my code?
What you need is an interface with your friend the Strategy pattern. For example:
public interface ISlice
{
public Slider Slide {get;set;}
}
public class Slice1 : ISlice
{
public Slider Slide { get; set; }
}
public static class SliceSlider
{
public static void DoSomethingCoolWithTheSliceSlide(ISlice slice)
{
slice.Slide.LookitMeIAmLearningDesignPatterns();
}
}
Writing less code shouldn't be your goal. In the end it's all about TCO (Total cost of ownership).
While owning less code can improve the TCO, there is one factor that has a much greater impact for TCO: maintainability. You should write the most maintainable code. Start by reading Robert Martin's Clean Code.
Update:
Also you say “I have lots of comments”. This is a point where you might improve your code. As you will learn from Martin’s book, good code hardly needs any comments. Martin says that “comments are lies” and “should be reserved for technical notes about the code and design.”.
Update 2:
While I'm add it, here are my favorite quotes from Robert Martin's book:
- "a class or module should have one, and only one, reason to change [Single Responsibility Principle]" [page 138]
- "More than three [method arguments] is very questionable and should be avoided with prejudice." [page 288]
- "The First rule of functions is that they should be small. The second rule of functions is that they should be smaller than that." [page 34]
- "Functions should hardly ever be 20 lines long" [page 34]
- "The statements in a function should all be written at the same level of abstraction" [page 304]
- "Comments should be reserved for technical notes about the code and design." [page 286]
I tend to agree with Steven. Writing less code, or fewer lines, is not always the goal. Thinking back to some of the stories of Steve Wozniak he used to make very compact hardware, putting tons of logic into a very small package, but very few people could follow what he did, maintain it, or manufacture it.
That being said, I suggest you get very familiar with Design Patterns. They may not lessen your lines of code but they may make you code easier to write, maintain, and understand. And a lot of times they do reduce the number of lines you have. Here are some resources:
DoFactory Design Patterns Reference
Wikipedia Design Pattern Acticle
Interfaces and abstract classes are a very strong part of the .net platform.
An interface is nothing more than a contract requirement on a class. That is: an interface is a defined set of methods and/or properties that a class implementing that interface must have. An interface is just a contract declaration.
An abstract class is really powerful because you can carry logic 'into' classes that implement that abstract class. But that is a whole other ball game.
Consider:
public interface ISlice
{
bool DoStuff(string someParameter);
}
public class MySpecificSliceOfType : ISlice
{
// this must have a method implementation for the [bool DoStuff(string)] method
public bool DoStuff(string mySpecificParameter)
{
// LOGIC in the Specific class
return(true);
}
}
public class MyOtherSliceOfType : ISlice
{
// this must have a method implementation for the [bool DoStuff(string)] method
public bool DoStuff(string myOtherParameter)
{
// LOGIC in the Other class
return(true);
}
}
Whilst this is a heavily oversimplified example, declaring the Interface implentation of the ISlice interface on both the classes 'MySpecificSliceOfType' and 'MyOtherSliceOfType' means that the requisite DoStuff() method is regardless of which one you have because you can do things like:
bool sliceReturn = ((ISlice)currentSlice).DoStuff(currentStringParameterValue);
This can save you working through in things like:
bool sliceReturn = false;
switch(typeofSlice)
{
case "other" :
sliceReturn = MyOtherSliceOfType.DoStuff(currentStrignParamterValue);
break;
case "specific" :
sliceReturn = MySpecificSliceOfType.DoStuff(currentStrignParamterValue);
break;
}
The point being illustrated here is even stronger when you have > 2 different types.
And interfaces and abstract classes combine nicely with the C# type checking stuff too.
Interfaces are a fundamental in Reflection ... something to be used very sparingly but understodd because it can save so much in specific cases ... and in Serialisation (a.k.a. Serialization) which can really help you fly.
Since you can't really post any of your code, I might as well throw out a random thought. Can you put these slices into an array? If so you might be able to get rid of some of the redundant code by having each of the controls set a variable (I'll call it whichSlice
). so the controls all set whichSlice
to the proper number 1-4 and then you run a normal switch and call slices[whichSlice].my.commands();
精彩评论