[Tutor] domain logic and avoiding setters and setters.
Kent Johnson
kent37 at tds.net
Tue Jul 12 14:19:16 CEST 2005
David Driver wrote:
> So I have been trying to figure out how to get around doing getters
> and setters and still have an oo way to inherit and apply business
> rules. This is what I have some up with so far. Is there any better
> way?
Hmm. I'm not sure what this has to do with getters and setters...maybe I would have to see the way you *didn't* show us to understand...
The only thing that I don't like about the code below is the need for subclasses to add rules to self._rules in the __init__() method. IMO this is fragile - it is too easy to forget to add or remove a rule from the list when the code changes.
An alternative is to use some form of auto-discovery of the rules. If you use a naming convention for the rule methods this is pretty easy. You can see an example in the unittest module; it finds all TestCase methods that start with 'test' and runs them. The code to find the tests is in Lib\unittest.py in the function getTestCaseNames().
Kent
>
> class RuleViolationError(Exception):
> def __init__(self, msg):
> self.msg = msg
> def __str__(self):
> return 'Rule violated in rule object: %s' %self.msg
>
> class someObject(object):
> def __init__(self,a):
> self._voilatedRules = {}
> self._rules = [self.aRuleForA]
> self.a = a
>
> def applyRules(self):
> self._voilatedRules.clear()
> for rule in self._rules:
> try:
> rule()
> except RuleViolationError, err:
> self._voilatedRules[rule.__name__] = err.msg
> if self._voilatedRules:
> # do something dramatic to deal with all of the
> # voilated business rules
> print 'error(s): '
> print self._voilatedRules
>
> def aRuleForA(self):
> try:
> self.a = int(self.a)
> except ValueError:
> raise RuleViolationError('a is not an integer')
>
> class someObjectChild(someObject):
> def __init__(self, a,b):
> someObject.__init__(self,a)
> self.b = b
> self._rules.extend((self.aRuleForB,
> self.anotherRuleForB))
>
> def aRuleForB(self):
> # apply some business logic for d
> # check that it starts with b, very silly
> if not self.b.startswith('b'):
> raise RuleViolationError('b does not start with b')
>
> def anotherRuleForB(self):
> #test string for length constraints
> min,max,l=2,15,len(self.b)
> print min,max,l
> if not(l>=min and l<=max):
> raise RuleViolationError('b is out of min or max')
>
> class someObjectChild2(someObjectChild):
> #j ust change one of the rules for b
> def aRuleForB(self):
> # apply some business logic for d
> # check that it starts with d, very silly
> if not self.b.startswith('d'):
> raise RuleViolationError('b does not start with d')
>
>
> x = someObjectChild(123,'bob jones')
>
> # this should return nothing
> x.applyRules()
> x.b = 'obladiobladalifegoesonOOOO'
>
> # this should fail twice on b
> x.applyRules()
>
> y = someObjectChild2(123,'bob jones')
> y.applyRules()
>
> z = someObjectChild('happydance','bob jones')
> z.applyRules()
>
> This isn't near complete, but I think it gets the idea across.
More information about the Tutor
mailing list