Rule 1: Use the description term or architecture of the current platform
One of the most common API error designs is the use of foreign rules, APIs belonging to a specific platform and the associated developer ecosystem. You can't use any of the different platform's descriptive terms or architectures, which can contaminate your current code base and disrupt your peers ' productivity.
Be fully aware of your target platform and code specifications before coding. For example, in iOS and OSX, the exception mechanism is not used to handle errors. Uniform naming rules (rules should be detailed enough, but concise enough).
Learn what is protocol (protocol), delegate (delegate), Extension (category). Always use terminology in your code. Obey the naming scheme for constructors and destructors. Adhere to local memory management rules.
Just as words and grammar are inseparable in natural language, your style must conform to the specified platform.
Rule 2: Design decoupling
The design should not associate the component with the project that created the component, and if it is a GUI component or view, it should display some default content. Use the existing framework as a guideline to keep interactions such as the Trust Protocol (Delegateprotocols) loosely coupled, with appropriate use notifications, and to be aware of good design and naming rules.
To do this, it is a very effective way to create a separate test project for each component. Forcing components to use only their own APIs. Do not extract the common denominator between unrelated classes.
Let's take a look at the interface of the class. The initialization method is one of the most important parts of the class interface, and it determines how the user uses your component. Your class needs to initialize some of the necessary configurations. So, a clear rule is as follows:
Rule 3: The required initialization conditions should be provided by the parameters
If there are any necessary initialization settings, do not wait for it to be provided when needed, but to be provided by the initialization parameters before needed. If initialization does not get the desired condition, it returns Null (nil) immediately.
// need parameter, cannot be Nil
- (ID)initwithdelegate:(ID<mgtilemenudelegate> )thedelegate;
Rule 4: Allow access to initialization parameters
This is a continuation of the previous rule: remember not to hide the parameters provided by the user at initialization time inside the module. To give users access to them, and notice whether they can be modified in some way (purged, or modified in other ways).
// must be specified by initialization method
@property (nonatomic, weak, readonly) ID<Mgtilemenudelegate > delegate;
This is a common example of the above two rules.
Rule 5: Comment Your header file
In fact, you will not always provide a separate document to describe the functionality of the code. If you do not provide a separate document, then your. h file (and the demo program) is your document. They should be "properly" annotated, and what is said here is appropriate to refer to:
1: detailed enough, but not too long. Be concise enough.
2: For Professionals (languages and vocabularies). All assumptions must be safe enough to be cautious. Don't be a baloney, don't be vague.
In particular, you should briefly describe the parameters, the functionality of the properties, and the default values. Make it easy for users to retrieve code functionality in the header file without having to look at the executable code section.
//Tile Background Gradient(Default:Blue)
@property(Nonatomic)CggradientrefTilegradient;
Default:5 pixels
@property ( Nonatomic) Nsintegerselectionborderwidth;
//default: Black ( bottom ) white ( Top ) Gradient
@property (nonatomic) cggradientrefselectiongradient;
Rule 6: Integrate to run no more than 3 lines of code
Your class should be designed to be integrated into the project (excluding the delegate/data source protocol, etc.) with minimal code. Without the proxy (delegate) method, your users should use only three lines of code to perform the simplest tests, namely:
1: Instantiation
2: Basic configuration.
3: Show or activate it.
The following is a code demonstration from Mgtilemenu:
// instantiation of.
Tilecontroller =[[MgtilemenucontrollerAlloc]Initwithdelegate:Self];
// Configuration .
tilecontroller. Dismissaftertileactivated = no; // makes it easier to play
// display .
[tilecontroller Displaymenucenteredonpoint:locinview:self. View
Rule 7: A cumbersome demo program usually means that the components function piecemeal
Another corollary: the size of your demo program determines the quality of the component, and the smaller the demo program, the better. The required code for the demo should be as small and simple as possible (but also to demonstrate the component's customized service or functionality in the demo).
With an empty Xcode template, you should only need to add very little code to create an app with the core functionality of your component. Simply providing a demo program is not enough, and you must also make sure that the copy-and-paste sample program you provided will work as well.
Rule 8: Set up a scheduled plan
The standard rule of my development application is not to give the user configuration options, but to choose a reasonable default value to apply to most users. Good software, always opinionated.
In this regard, the components and applications are different because the usage scenarios for the components are ambiguous. Of course, you can make a component available only to a particular situation, but usually we prefer the component to have some flexibility. You never know how other developers will use your component, so you have to make it a certain commonality.
It is important to carefully consider the features supported by the component. In particular, consider dependencies-not dependencies at compile/link time, but dependencies between logical functions and interfaces. My approach is not to think about the problem at the level of the instance variable (member), but to think about it from a "custom scheme" level. Figure out what customization options you want your component to have? Then, based on these custom schemes, choose which properties to expose to the consumer.
A very easy mistake is to expose a lack of configuration items (interfaces) that weaken a feature, such as the following examples:
1: Width and height settings are exposed, but rounded corners are not considered.
2: The background color setting is exposed, but the background color setting is not considered when highlighting.
3: Size setting is disclosed, but spacing is not considered.
This error usually depends on the specific component and tries to consider the relationship between attributes from the perspective of the display effect and function. Consider the issue from the user's perspective. Be flexible and easy to use, but do not discard the features of the component.
// tile is activated after the menu is lifted(YES;default)
@property(Nonatomic)BOOLdismissaftertileactivated;
// Right-hand mode(YES;default) or left-handed mode(NO)
@property(Nonatomic)BOOLrighthanded;
// the width and height of each tile,Unit:Pixel(default thePixel)
@property(Nonatomic)NsintegerTileside;
// Tile Spacing, Unit:Pixel(default:Pixel)
@property(Nonatomic)nsintegertilegap // radius of tile fillet , units : Pixels ( default : 12.0 pixels )
(nonatomic) cgfloatcornerradius
Let common sense guide you. Find the options that will be used in 70% cases and provide these options to the user.
Rule 9: More features, fewer operations
In my favorite components (some of them are standard frameworks, some are open source components from third parties, and I wrote them myself), there is a feature that often comes up. The functions implemented by the component (all functions, from initialization to state update, etc.) and the exposed interfaces (accessors or custom methods, etc.) have some proportional relationships.
These components are almost always implemented with fewer operations (this is not an interface operation, but an interface) to achieve more features. Mgtilemenu has an initialization and four function methods (one of which is the simplification of the other), which is four times times proportional to its characteristics and operation. I think this is a good proportion, in a concise and practical functions, but also flexible customization.
// parameter cannot beNil
-(Id)initwithdelegate:(Id<Mgtilemenudelegate>)Thedelegate;
// from0start
-(Cgpoint)Displaymenupage:(Nsinteger)PagenumCenteredonpoint:(Cgpoint)CenterptInView:(UIView *)parentview -void) dismissmenu // from 0 start
-void) switchtopage: (nsintegerpagenum< Span style= "color: #586e75;" >;
Rule 10: Use controls in your control
A good way to simplify the API is to use the existing components in your component. Component style unification does not mean that you cannot use existing components to construct new components (in fact, this is a good software engineering principle).
For example, the APIs for UITableViewCell and UIButton are so simple because they use child controls Uilabels and Uiimageviews. If appropriate, you can do the same-and expose the child controls to make your current class interface more concise and consistent.
For example Mgtilemenu, tiles are extended by uibuttons. This simplifies a lot of work compared to drawing in custom views and tracking input, providing access to the interface.
Rule 11: Your convenience method may also be suitable for users
You will certainly add some handy methods during the authoring component, and instinctively set them to private. In fact, you can consider whether users will use these methods when integrating your components to determine whether they are exposed (public).
For example, I created these handy features in Mgtilemenu:
CGRectmgminimallyoverlaprects(CGRectinner cgrectoutercgfloat Padding);
//rgb color gradient
cggradientref mgcreategradientwithcolors (uicolor * uicolor * bottomcolorrgb);
The first is the structure of the storage location, which is used to move the menu so that it can be fully visible in its parent view (making it easy for other developers to create menus that match their own UI). The second is the structure that stores the gradient, which is used to set the shape gradient for the menu background (the caller is notified by a delegate when the background changes).
Rule 12: The magical effect is good, the magic number is not
Sooner or later you will put something peculiar in the component. and want to give more delightful magical features like Steve Jobs. But what I'm going to say is a number that has a special meaning in your code. One of the most common examples is 1, which is usually used to denote a particular set of things, or special cases.
It is correct to use a specific value to represent a class of situations. So what's wrong with that? Obviously, you can't use this mysterious primitive value directly in your code, especially if you can't expose it to the API. If you have to expose it, please wrap it up, such as using #defines to define a name that can be understood.
Component Interface (API) Design Guide [2]-class Interface (interface)