most explicit specification in specification pattern for strategy -
say have lot of business logic determine app behavior based on multiple factors. also, have places know can replace behavior strategy pattern. also, considering i'm trying leverage various patterns solve problem
- strategy pattern
- specification pattern
- factory pattern
is possible use specification pattern determining strategy in factory , retain open closed principle?
i have factory , find myself creating switch statements former code pick correct strategy. seems counter productive.
i want push these logical decisions off specifications problem arises ordering specifications or picking explicit specification first.
any idea how solve this?
using system; using system.collections.generic; using system.linq; using static beyondoop.gender; // having make decisions based on logic // control flow without nested if namespace beyondoop { class program { static void main(string[] args) { var people = new list<person> { new person("bill", new datetime(1940, 10, 10), male), new person("jill", new datetime(1950, 10, 10), female), new person("mary", new datetime(2015, 10, 10), female), new person("gary", new datetime(1970, 10, 10), male), new person("greg", new datetime(1980, 10, 10), male), new person("susan", new datetime(2013, 10, 10), female), new person("gabe", new datetime(1999, 10, 10), neutral), new person("barbie", new datetime(2000, 10, 10), female), }; var greeter = new persongreeter(); people.foreach(greeter.greet); } } // little 'generics' flair // 'predicate' way // predetermine true false interface ipredicate<t> { bool matches(t value); } // simple dto // data transfer object, fancy value container // it's way of passing values around class person { public string name { get; } public datetime dateofbirth { get; } public gender gender { get; } public person(string name, datetime dateofbirth, gender gender) { name = name; dateofbirth = dateofbirth; gender = gender; } } enum gender { male, female, neutral } // prefabed predicates 'person' class oldmanpredicate : ipredicate<person> { public bool matches(person value) => (datetime.now.year - value.dateofbirth.year) >= 60 && value.gender == gender.male; } class minorpredicate : ipredicate<person> { public bool matches(person value) => datetime.now.year - value.dateofbirth.year < 18; } class toddlerpredicate : ipredicate<person> { public bool matches(person value) => datetime.now.year - value.dateofbirth.year > 2 && datetime.now.year - value.dateofbirth.year < 4; } class babypredicate : ipredicate<person> { public bool matches(person value) => datetime.now.year - value.dateofbirth.year <= 2; } class truepersonpredicate : ipredicate<person> { public bool matches(person value) => true; } class greetaction { public func<person,bool> predicate { get; } public func<person,string> messager { get; } public greetaction(func<person, bool> predicate, func<person, string> messager ) { predicate = predicate; messager = messager; } } class persongreeter { // may if you're using func // why go through trouble of // classes. predicate classes can added freely // factory class needs changed // , if create factory predicates // , messagers no changes neccessary private readonly list<greetaction> _greetactions = new list<greetaction> { // these have ordered // don't conflict or override // intended behavior // minorpredicate < 18 babies , toddlers // less 18, need preceed minors work new greetaction( new oldmanpredicate().matches, p => $"{p.name}, you're getting there!"), new greetaction( new babypredicate().matches, p => $"{p.name}, time change diaper!"), new greetaction( new toddlerpredicate().matches, p => $"{p.name}, look, you're walking!"), new greetaction( new minorpredicate().matches, p => $"{p.name}, no, may not have beer!"), // need default action // same 'null pattern' new greetaction( new truepersonpredicate().matches, p => $"{p.name}, hello there!"), }; public void greet(person person) => console.writeline(_greetactions .first(p => p.predicate(person)) .messager(person)); } }
Comments
Post a Comment