Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I think you are right in making the validator validate the entire model. To break the infinite loop, you can pass the value to the validator</p> <pre><code>Public Property Get UserID() UserID = m_Validator.IsUserIDValid(m_userID) End property // in Validator Public Function IsUserIDValid(userID) IsUserIDValid = userID &gt; 13 End Function </code></pre> <p>Alternatively, if you prefer encapsulation, you can add Friend functions for accessing the property without validation.</p> <pre><code>Public Property Get UserID() UserID = m_Validator.IsUserIDValid() End property Friend Function GetUserID() GetUserID = m_userID End Function // in Validator Public Function IsUserIDValid() // "private" access - to get the unvalidated property IsUserIDValid = m_user.GetUserID &gt; 13 End Function </code></pre> <p>A third way to do this is to separate your object from validation. The base class defines all the properites without validation. Then you define a child class that adds validation:</p> <pre><code>class User Private m_userID Public Property Get UserID() UserID = m_userID End property End Class class ValidatedUser inherits User Public Overrides Property Get UserID() if (m_userID&lt;15) // handle invalid case, e.g. throw exception with property that is invalid UserID = m_userID End Property Public Function Validate() ' class-level validation End Function End Class </code></pre> <p>A final variation uses delegation to keep the basic user properties separate from the validated ones. We make User an abstract class, since we have to implementations - one with validation, and one without.</p> <pre><code>Class MustInherit User Public MustInherit Property Get UserID() End Class ' A simple implementation of User that provides the properties Class DefaultUser Inherits User Private m_UserID Public Overrides Property Get UserID() UserID = m_UserID End Property End Class Class ValidatedUser Inherits User private Validator m_validator private User m_User Public Property Let Validator(value) Set m_Validator = value m_Validator.Initialize(m_User) ' note that validator uses m_User - this breaks the infinite recursion End Property Public Overrides Property Let UserID(value) m_User.UserID = value; End Property Public Overrides Property Get UserID() UserID = m_validator.IsUserValid(); End Property End Class </code></pre> <p>In the last example ValidatedUser looks similar to your original code, but the key difference is that ValidatedUser itself doesn't have any property values - it delegates all property accessors to the m_User object. The Validator uses the m_user object which provides simple properties without validation, so the infinite recursion goes away.</p> <p>At present, validation is done when the property is retrieved. I imagine this is done because you want to validate the data before it's used, and to avoid transient validation errors as properties are assigned. In addition to property-level validation, you may want to also define a "whole object" validation method that checks all properties on your object, particularly those involved in multi-property constraints. For example, if you have the constraint A+B+C &lt; 50, then checking A B and C as separate properties will lead to that condition (A+B+C&lt;50) being evaluated 3 times, which is unnecessary, and also confusing since the error will appear on one specific property, when it's really a problem with all 3 properties. Your object-level validator can check this condition just once and flag an error that indicates all 3 properties are not valid.</p> <p>All of the above bind the Validation to the User class, so that clients can use User without concern for validation. There are benefits and drawbacks with this approach. The benefit is transparency - client's can use User objects and get validation behind the scenes without explicitly asking for it. The downside is that it ties validation very tightly in with your model. An alternative is to completely separate validation from the User object. This not only decouples validation, but also provides for "whole-object" validation. E.g.</p> <pre><code>' User is now a simple class (like DefaultUser above ' ' with just properties, no validation ' Class UserValidator Public Function Validate(user) ' validate the given user object, return a list of ' validation errors, each validation error object ' that describes the property or properties ' that caused the validation error and why it's an error ' E.g. ' Dim ve As ValidationError ve = new ValidationError ve.obj = user; ' the object that failed validation ve.property = "userID" ve.msg = "userId must be &lt; 15" ' potentially put several of these in a list and return to caller End End Class </code></pre> <p>Any code manipulating User will then have to explicitly call Validate after making changes, but this is usually not a problem, and the level of control is much better than having it done automatically. (In my experience,you almost always have to undo "automatic" actions at some point because they get in the way.)</p> <p>I wrote more than I intended. I hope this is helpful!</p> <p>PS: I don't do much VB, so please be lenient of the occasional syntax error. I am an OO programmer, so I know the principles are correct. And I just noticed the "asp-classic" tag - some of the examples use features that may not be available in classic asp, although the separate Validator code - the last example, should be fine on classic asp.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload