diff --git a/README.md b/README.md index d585e74..5c6e069 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ The goal is to have a set of [GOF patterns](http://www.blackwasp.co.uk/gofpatter - [Bridge](structural/bridge.cr) - [Composite](structural/composite.cr) - [Decorator](structural/decorator.cr) + - [Facade](structural/facade.cr) + - [Flyweight](structural/flyweight.cr) ## Contribution diff --git a/structural/facade.cr b/structural/facade.cr new file mode 100644 index 0000000..0665899 --- /dev/null +++ b/structural/facade.cr @@ -0,0 +1,68 @@ +# The facade pattern is a design pattern that is used to simplify access +# to functionality in complex or poorly designed subsystems. +# The facade class provides a simple, single-class interface that hides +# the implementation details of the underlying code. + +# ----------------- Complex or poorly designed library ----------------------- +class Arena + @round : Round? + + property round + + def initialize(@name : String) + load_arena(@name) + end + + def load_arena(name : String) + puts "Loading arena #{name} from disk..." + end +end + +class RoundManager + def define_round(arena : Arena, round_params : RoundParams) + check_round_params(round_params) + arena.round = Round.create_with_params(round_params) + end + + def check_round_params(params : RoundParams) + puts "Checking validity of round parameters..." + end +end + +class Round + def initialize(@time : Int32, @matches : Int32) + puts "Round initialized with duration #{@time}s and #{@matches} matches." + end + + def self.create_with_params(params : RoundParams) + Round.new(params.time, params.matches) + end +end + +struct RoundParams + property time, matches + + def initialize(@time : Int32, @matches : Int32) + end +end + +# ---------------------------------------------------------------------------- + +# Facade provides simplified access to the complex API +class Facade + DEFAULT_TIME = 60 + DEFAULT_MATCHES = 3 + + def self.create_default_arena : Arena + arena = Arena.new("default") + rm = RoundManager.new + params = RoundParams.new(DEFAULT_TIME, DEFAULT_MATCHES) + rm.define_round(arena, params) + arena + end +end + +Facade.create_default_arena +# Loading arena default from disk... +# Checking validity of round parameters... +# Round initialized with duration 60s and 3 matches. diff --git a/structural/flyweight.cr b/structural/flyweight.cr new file mode 100644 index 0000000..cd2fe99 --- /dev/null +++ b/structural/flyweight.cr @@ -0,0 +1,81 @@ +# The flyweight pattern is a design pattern that is used to minimise +# resource usage when working with very large numbers of objects. +# When creating many thousands of identical objects, stateless flyweights +# can lower the memory used to a manageable level. + +alias Position = {Int32, Int32} + +# Contains the extrinsic actions that the object can do. +abstract class FlyweightTree + abstract def draw_at(pos : Position) +end + +# Implements the Flyweight interface, optionally keeping an extrinsic state +# which can be manipulated via that interface. +class Tree < FlyweightTree + property pos + + def initialize(species : String) + # Intrinsic (stateless) properties. These are shared between all instances of this tree. + @species = species + # Estrinsic (stateful) properties. These are accessed via the abstract interface + # provided by FlyweightTree + @pos = {0, 0} + end + + def draw_at(_pos : Position) + pos = _pos + puts "Drawing #{@species} at #{pos}" + end +end + +# Factory class for the flyweight objects. +class Forest + def initialize + @trees = {} of String => FlyweightTree + end + + def get_tree(species : String) + if @trees.has_key?(species) + @trees[species] + else + Tree.new(species).tap { |tree| @trees[species] = tree } + end + end + + def tot_instances + @trees.size + end +end + +# Client code +forest = Forest.new +forest.get_tree("birch").draw_at({5, 6}) +forest.get_tree("acacia").draw_at({3, 1}) +forest.get_tree("magnolia").draw_at({15, 86}) +forest.get_tree("birch").draw_at({8, 15}) +forest.get_tree("acacia").draw_at({18, 4}) +forest.get_tree("baobab").draw_at({1, 41}) +forest.get_tree("magnolia").draw_at({80, 50}) +forest.get_tree("acacia").draw_at({22, 3}) +forest.get_tree("birch").draw_at({1, 42}) +forest.get_tree("baobab").draw_at({15, 7}) +forest.get_tree("acacia").draw_at({33, 49}) +forest.get_tree("magnolia").draw_at({0, 0}) +puts "-----------------------" +puts "Total instances created: #{forest.tot_instances}" + +# Drawing birch at {5, 6} +# Drawing acacia at {3, 1} +# Drawing magnolia at {15, 86} +# Drawing birch at {8, 15} +# Drawing acacia at {18, 4} +# Drawing baobab at {1, 41} +# Drawing magnolia at {80, 50} +# Drawing acacia at {22, 3} +# Drawing birch at {1, 42} +# Drawing baobab at {15, 7} +# Drawing acacia at {33, 49} +# Drawing magnolia at {0, 0} +# ----------------------- +# Total instances created: 4