写点什么

架構師訓練營 week3 總結

用户头像
ilake
关注
发布于: 2020 年 10 月 04 日

设计模式:使用设计模式优化排序工具包的设计

什麼是設計模式
  • 每一種模式都描述了一種通用的解決方案

  • 一種可重覆使用的解決方案



設計模式的四個部分
  • 模式的名稱

  • 待解問題

  • 解決方案

  • 結論



設計模式的分類
  • 從功能分

  • Creational Pattens

  • 從方式分

  • 類模式



Simple Factory Pattern

from

class RuleConfigSource
def load(file_path)
rule_config_file_extension = get_file_extension(file_path)
parser = case rule_config_file_extension.downcase
when 'json'
JsonRuleConfigParser.new
when 'xml'
XmlRuleConfigParser.new
when 'yaml'
YamlRuleConfigParser.new
end
parser
end
private
def get_file_extension(file_path)
# parse file extension
return 'json'
end
end

to

# use simple_factory patten to extract “case when” to RuleConfigParserFactory.

RuleConfigSource => OOP

class RuleConfigSource
def load(file_path)
rule_config_file_extension = get_file_extension(file_path)
parser = RuleConfigParserFactory.create_parser(rule_config_file_extension)
parser
end
private
def get_file_extension(file_path)
# parse file extension
return 'json'
end
end



class RuleConfigParserFactory
def self.create_parser(rule_config_file_extension)
case rule_config_file_extension.downcase
when 'json'
JsonRuleConfigParser.new
when 'xml'
XmlRuleConfigParser.new
when 'yaml'
YamlRuleConfigParser.new
end
end
end

Factory Pattern

class RuleConfigSource
def load(file_path)
rule_config_file_extension = get_file_extension(file_path)
parser_factory = RuleConfigParserFactoryMap.get_factory(rule_config_file_extension)
parser = parser_factory.create_parser
parser
end
private
def get_file_extension(file_path)
# parse file extension
return 'json'
end
end



class RuleConfigParserFactoryMap
Factory_Map = {
json: JsonRuleConfigParserFactory,
xml: XmlRuleConfigParserFactory,
yaml: YamlRuleConfigParserFactory
}
def self.get_factory(type)
return nil unless type
Factory_Map[type.to_symbol]
end
end



class JsonRuleConfigParserFactory
include RuleConfigParserFactoryInterface
def create_parser
JsonRuleConfigParser.new
end
end



Simple Factory VS Factory

  • If the initialize part is easy, use “Simple Factory"

Singleton Pattern

Singleton

  • Reduce resource-consuming => performance requirement

  • Easy to control (only one instance) => feature requirement

Need to consider

  • Make the default constructor private, to prevent other objects from using the new operator with the Singleton class.

  • Thread-safe?

  • Lazy loading?

  • Performance for getting instance

    

How to implement it?

  • Eager load

  • Lazy load

  • Lazy load but reuse

  • Static internal class

  • Hash



What problems?

  • Not OOP

  • Program to an interface, not an implementation

  • Hide the Dependency between classes

  • Not good to test

  • Because that is global, if someone updates it, it is not easy to find

thread-safe_singleton.rb
class Singleton
attr_reader :value
@instance_mutex = Mutex.new
private_class_method :new
def initialize(value)
@value = value
end
def self.instance(value)
return @instance if @instance
@instance_mutex.synchronize do
@instance ||= new(value)
end
@instance
end
def some_business_logic
end
end



naive_singleton.rb
class Singleton
@instance = new
private_class_method :new
def self.instance
@instance
end
def some_business_logic
end
end

Adapter Pattern

Adapter =>  allows objects with incompatible interfaces to collaborate.

  • Class adapter => inheritance

  • Object adapter => assemble



Some use cases:

  • Encapsulate flawed interface design

  • Unify multiple classes' interfaces

  • Replace 3rd-party’s interfaces

  • New/Old versions compatible

  • Adapter different data formats



Wrapper Patterns

  • Adapter: provide different interface, but Decorator and Proxy provide the same interface

  • Decorator: similar with Proxy, same interface, but strength original class’s functions

  • Proxy: similar with Decorator, same interface, do not strength function and but controlling access

class Target
def request
'default behavior'
end
end
class Adaptee
def specific_request
"adaptee's request"
end
end
class Adapter < Target
def initialize(adaptee)
@adaptee = adaptee
end
def request
"Adapter: #{@adaptee.specific_request.reverse}"
end
end
def client_code(target)
puts target.request
end
# original
target = Target.new
client_code(target)
# with adapter
adaptee = Adaptee.new
puts adaptee.specific_request
adapter = Adapter.new(adaptee)
client_code(adapter)



Template Pattern

Template Pattern:  defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.

  • Base Class define the structure

  • Sub Class implement the detail 



Mainly solve these problems

  1. Reuse

  2. Expand



3 types of methods for Template Pattern

  • Abstract method => mandatory for subclass

  • Base method => subclass can override but not mandatory

  • Hook => for subclass

class BaseClass
def template_method
base_1
need_child_1
hook_1
end
def base_1
puts "I'll do it"
end
def need_child_1
raise 'implement me'
end
# not mandatory
def hook_1; end
end
class ChildClass < BaseClass
def need_child_1
"I'm a kid, I do it"
end
def hook_1
"I also do hook"
end
end
def client_code(base_class)
base_class.template_method
end
client_code(ChildClass.new)

Strategy Pattern

Use to prevent long “if else” or “case"

Definition of strategy

  • Strategy interface, some ConcreteStrategy classes to implement

class DiscountStrategy
def discount(_data)
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
end
class NormalDiscountStrategy < DiscountStrategy
def discount(type)
# normal discount
end
end
class CouponDiscountStrategy < DiscountStrategy
def discount(type)
# coupon discount
end
end



How to build

  • Use factory patten to encapsulate the detail

class DiscountStrategyFactory
Stragegies = {
normal: NormalDiscountStrategyA.new,
coupon: CouponDiscountStrategyB.new
}
def self.get_stragegy(type)
raise 'type should be empty' unless type
Stragegies[type.symbol]
end
end

How to use

class OrderServie
def discount(order)
type = order.type
discount_strategy = DiscountStrategyFactory.get_stragegy(type)
discount_strategy.discount
end
end

Decorator Pattern

  • Decorator class and original class inherit from the same base case, then we can have many decorator classes

  • Original function enhancement

  • Proxy patten: add functions which are non-related with the original class

class Component
def operation
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
end
class ConcreateComponent < Component
def operation
'ConcreteComponent'
end
end
class Decorator < Component
attr_accessor :component
def initialize(component)
@component = component
end
def operation
@component.operation
end
end
class ConcreteDecoratorA < Decorator
def operation
"ConcreteDecoratorA #{@component.operation}"
end
end
class ConcreteDecoratorB < Decorator
def operation
"ConcreteDecoratorB #{@component.operation}"
end
end
————
def client_code(component)
puts component.operation
end
simple = ConcreteComponent.new
client_code(simple)
decorator1 = ConcreteDecoratorA.new(simple)
decorator2 = ConcreteDecoratorB.new(decorator1)
client_code(decorator2)

Composite Pattern

Composite: Compose objects into tree structure to represent part-whole hierarchies.Composite lets client treat individual objects and compositions of objects uniformly.



將一組對象組織成樹狀結構,單個對象和組合對象都是樹中的節點,統一處理邏輯

利用樹狀結構,遞迴處理每個子樹

class FileSystemNode
def initialize(path)
@path = path
end
def count_num_of_files
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
def get_path
@path
end
end
class File < FileSystemNode
def count_num_of_files
1
end
end
class Directory < FileSystemNode
def initialize(path)
@path = path
@sub_nodes = []
end
def count_num_of_files
num_of_files = 0
@sub_nodes.each do |sub_node|
num_of_files += sub_node.count_num_of_files
end
num_of_files
end
def add_sub_node(file_or_dir)
@sub_nodes << file_or_dir
end
def remove_sub_node(file_or_dir)
@sub_nodes.delete(file_or_dir)
end
end
file_system_tree = Directory.new('/')
dir_1 = Directory.new('/1/')
dir_2 = Directory.new('/2/')
file_system_tree.add_sub_node(dir_1)
file_system_tree.add_sub_node(dir_2)
file_a = File.new('/1/a.txt')
file_b = File.new('/1/b.txt')
dir_11 = Directory.new('/1/11/')
dir_1.add_sub_node(file_a)
dir_1.add_sub_node(file_b)
dir_1.add_sub_node(dir_11)
puts file_system_tree.count_num_of_files



用户头像

ilake

关注

还未添加个人签名 2019.04.15 加入

还未添加个人简介

评论

发布
暂无评论
架構師訓練營 week3 總結