Presentation is loading. Please wait.

Presentation is loading. Please wait.

1)Never start coding unless you understand the task! 2)Gather requirements first. This means identify the problem and ask questions about it. Now you kind.

Similar presentations


Presentation on theme: "1)Never start coding unless you understand the task! 2)Gather requirements first. This means identify the problem and ask questions about it. Now you kind."— Presentation transcript:

1 1)Never start coding unless you understand the task! 2)Gather requirements first. This means identify the problem and ask questions about it. Now you kind of know what to do. 3)Analyze requirements to make sure that they are consistent and complete. Now you know that whatever you are going to do is doable. 4)Produce technical specification (i.e. express the requirements in technical terms). Now you know exactly what to do. 5)Think of what steps you need to take solve the problem and express them verbally to obtain a high- level process description. Now you have a process that you can code! 6)Start coding. Problem Solving

2 * Split complex task in a series of simple steps. * Identify entities the problem deals with. These will be your classes. * Identify what data characterizes your entities. These will be your class properties. * Identify what actions your entities can perform. These will be your class methods. * Find repeated actions and generalize them. These will be your utility functions or utility classes. You will reuse them. * Don’t make any assumptions: check user input and make provisions for worst cases. Process Analysis

3 Problem: Determine if the email address is valid. Requirement analysis: What rules can we define to check email address against? What is email address comprised of? max.fomitchev@cse.psu.edu Local Part @ domain subdomain1.subdomain2.tld Email Validation Task

4 Core Rules Single ‘@’ character Non-empty Local Part Non-empty domain Non-empty subdomain(s) Non-empty TLD Local Part must not end with ‘.’ Additional Rules 7) 1 < TLD length < 7 8) Local Part length < 65 9) Domain Length < 256 11) Subdomain(s) must not begin with ‘-’ or end with ‘-’ 12) Check for invalid characters: ‘\\’, ‘”’, ‘ ’, ‘)’, ‘(‘, ‘]’, ’[‘, ’;’, ‘,’, ‘:’, ‘|’ 13) Domain cannot contain two ‘-’ in a row 14) Check TLD against the list of ICANN domains Email Validation Rules

5 General There has to be LocalPart and Domain separated by ‘@’ Must not contain general illegal characters (‘\\’, ‘”’, ‘ ’, ‘)’, ‘(‘, ‘]’, ’[‘, ’;’, ‘,’, ‘:’, ‘|’) LocalPart 0 < Length < 65 Must not end with ‘.’ Domain 0 < Length < 256 There has to be at least one subdomain and a TLD separated by ‘.’ Must not contain ‘@’ All subdomains must be valid TLD must be valid Subdomain 0 < Length < 64 Must not begin or end with ‘-’ TLD 0 < Length < 7 Must not contain ‘-’ OR limit TLD choices to domains from ICANN list. Optimized Rules / Technical Spec

6 Design Choice: Buffer Allocation Since you do not know sizes of strings you deal with… a)Do you make an assumption of max string length and allocate fixed-size string buffers on stack? +simpler +faster +robust -limited b)Or do you allocate memory on heap (e.g. using the new operator)? -harder -slower -err.prone +universal

7 Choice A: Fixed Buffers // Our Assumptions #define MAX_LOCAL_PART65 #define MAX_DOMAIN256 #define MAX_SUBDOMAIN64 #define MAX_TLD7 #define MAX_SUBDOMAINS10 // Buffers char LocalPart[MAX_LOCAL_PART]; char Domain[MAX_DOMAIN]; char TLD[MAX_TLD]; char Subdomain[MAX_SUBDOMAINS][MAX_SUBDOMAIN];

8 Top-Level Class: Email Email – this is the one we validate -Contains Address string (property) -Contains LocalPart (property) -Contains Domain (property) -Can be parsed into LocalPart and Domain pieces (method) -Can be validated (method)

9 Email Class class Email { public: Email(char* address); public: String Address; EmailLocalPart LocalPart; EmailDomain Domain; public: bool Parse(); bool IsValid(); };

10 Other Classes LocalPart -Contains UserName string (property) -Can be validated (method) Domain -Contains Name string (property) -Contains an array of Subdomains (property) -Contains TLD (property) -Can be parsed (method) -Can be validated (method) Subdomain -Contains Name string (property) -Can be validated (method) TLD (closely similar to Subdomain but somewhat different) -Contains Name string (property) -Can be validated (method)

11 EmailLocalPart Class class EmailLocalPart { public: EmailLocalPart(); public: String UserName; public: bool IsValid(); private: char UserNameBuffer[MAX_LOCAL_PART]; };

12 EmailDomain Class class EmailDomain { public: EmailDomain() { SubdomainCount = 0; } public: String Name; EmailSubdomain Subdomain[MAX_SUBDOMAINS]; int SubdomainCount; EmailTld Tld; public: bool Parse(); bool IsValid(); private: char DomainBuffer[MAX_DOMAIN]; };

13 EmailSubdomain Class class EmailSubdomain { public: EmailSubdomain(); public: String Name; public: virtual bool IsValid(); // Virtual means that the method // can be replaced in a derived // class private: char NameBuffer[MAX_DOMAIN]; };

14 EmailTld Class // Subdomain and Tld are identical, except for // slight differences in validation rules, so to avoid repetition derive EmailTld class from EmailSubdomain base class class EmailTld: public EmailSubdomain // EmailTld class is derived from // EmailSubdomain class { public: EmailTld(); /* public: String Name; */ // Name is inherited from Subdomain // therefore no need to declare again public: virtual bool IsValid(); // Inherited, but we are going to // replace it since TLD validation // is different };

15 Email Checker Solution: Process 1)Separate email into LocalPart and Domain 2)Separate Domain into Subdomain[] array and TLD 3)Apply part validation rules to see if any of them are violated.

16 Separate Local Part & Domain 1)Determine email Length 2)Determine AtPosition: the position of ‘@’ character in email 3)Copy characters 0…AtPosition to LocalPart 4)Copy characters AtPosition+1…Length to Domain

17 Pretend that you have already solved concrete tasks (such as copying characters, finding character index, etc.) with the help of String utility class and proceed to construct your abstract solution by referring to String and other concrete classes that you have not yet implemented. Proceed from Abstract to Concrete

18 (!) Find repeated tasks that can be generalized and streamlined, e.g. a)Determining string length (i.e. return the ‘length’ of ‘this string’) b)Copying a range of characters from one string into another (i.e. copy ‘length’ characters from ‘this string’ starting at ‘startPosition’ into ‘destination’ c)Finding character index (find ‘aChar’ in ‘this string’ starting at ‘startPosition’) The above (a,b,c) deal with character strings. So let’s pretend that we have a String class that can do all of the above.Implementation

19 // String utility class class String { public: String() // Default constructor (builds uninitialized String) { Buffer = NULL; } String(char* buffer) // String encapsulates char-array pointer { Buffer = buffer; } public: int GetLength(); int IndexOf(char aChar, int startPosition); // !! Returns -1 when aChar is not found void CopyTo(int startPosition, int length, String& destination); bool IsValid() // Sanity check { return Buffer != NULL; } private: char* Buffer; }; String Class

20 String Class Encapsulates char* String class encapsulates char* pointer. Therefore a String must be initialized with a valid char* pointer! char nameBuffer[100]; String name(nameBuffer);

21 We always start with top-level class. So let’s pretend that Email class is done and the email validation works and we can use it, e.g. Email email(“max@adelphia.net”); if ( email.IsValid() ) cout << “Email is valid”; else cout << “Email is not valid”; Where Do We Start?

22 We start filling in blanks from the constructor of the top-level class. In the constructor we can refer to other classes we invented even though they are not yet implemented. Where Do We Go Next?

23 Just store the pointer to email address in internal property: Email::Email(char* address) { // Here we initialize Email’s internal // Address property of type String Address = String(address); } Constructor Email::Email()

24 Now, since we already know what amounts to valid email we can express Email::IsValid() concisely as follows: bool Email::IsValid() { // Separate email into LocalPart and Domain return Parse() &&// Was parsing OK? LocalPart.IsValid() &&// LocalPart OK? Domain.IsValid();// Domain OK? } bool Email::IsValid()

25 And we know how to parse EmailAddress into LocalPart and Domain: bool Email::Parse() { // Find ‘@’ character int atPosition = Address.IndexOf(‘@’, 0); if ( atPosition == -1 ) return false; // Shute, ‘@’ not found! Therefore cannot parse. // Determine email length int length = Address.GetLength(); // Copy email parts in appropriate buffers Address.CopyTo(0, atPosition, LocalPart.UserName); Address.CopyTo(atPosition + 1, Length - atPosition - 1, Domain.Name); return true; } Void Email::Parse()

26 And we know what rules we need to check to make sure that LocalPart is valid: bool EmailLocalPart::IsValid() { // We do not assume anything, so check UserName string if ( !UserName.IsValid() ) return false; int length = UserName.GetLength(); // Rule Check: length between 1 and 64 if ( length 64 ) return false; else return true; } bool EmailLocalPart::IsValid()

27 And we know what rules we need to check to make sure that Domain is valid: bool EmailDomain::IsValid() { // Extract subdomains and TLD if ( !Parse() ) return false; // Check subdomains for ( int i = 0; i < SubdomainsCount; i++ ) if ( !Subdomain[i].IsValid() ) return false; // Check TLD if ( TLD.IsValid() ) return true; else return false; } bool EmailDomain::IsValid()

28 And we know what rules we need to check to make sure that Domain is valid: bool EmailDomain::Parse() { // We do not assume anything, so check UserName string if ( !Name.IsValid() ) return false; // Contains at least one ‘.’ if ( Name.IndexOf(‘.’, 0) == -1 ) return false; // Reset SubdomainCount SubdomainCount = 0; // Extract subdomains int startPosition = 0; do { int nextPosition = Name.IndexOf(‘.’, StartPosition); if ( nextPosition != -1 ) Name.CopyTo(startPosition + 1, nextPosition - startPosition, Subdomain[SubdomainCount++]); else Name.CopyTo(startPosition + 1, nextPosition - startPosition, Tld) startPosition = nextPosition + 1; } while ( startPosition != 0 ); return true; } bool EmailDomain::Parse()

29 TLD is a domain, since all domain rule checking applies with an addition of one more TLD-specific rule: TLD cannot contain a ‘-’ // Constructor does nothing special, so we simply call // the base class constructor EmailTld::EmailTld() : EmailSubdomain() { } bool EmailTld::IsValid() { return EmailSubdomain::IsValid() && Name.IndexOf(‘-’, 0) == -1; } bool EmailTld::IsValid()

30 Just keep filling in the blanks and your program will be done! In the process you will likely modify your class definitions to accommodate your programming needs as you discover new things. Class design / programming is an iterative approach. Thus changing and going back and forth is inevitable and normal. And So On and So Forth


Download ppt "1)Never start coding unless you understand the task! 2)Gather requirements first. This means identify the problem and ask questions about it. Now you kind."

Similar presentations


Ads by Google