Это своего рода «архитектурное» решение на тот случай, если в вопрос встроена проблема xy .
- x не имеет структуры данных, которая хранит всех фрилансеров (и структуры данных, которая хранит всех клиентов).
- y , проблема в вашем вопросе, вытекает из использования объектов для инкапсуляции данных (это хорошее использование объектов).Это затрудняет работу с данными в совокупности.Например, при написании кода, который ищет всех фрилансеров.
Структура данных для агрегатов
В структуре данных используются Array
для @clients
и @freelancers
,Он обеспечивает add_freelancer
и add_client
, так что тип данных @clients
и @freelancers
может быть изменен на файл или базу данных без влияния на реализацию Client
или Freelancer
.
class MyDataStore
attr_accessor :clients, :freelancers
def initialize()
@clients = Array.new
@freelancers = Array.new
end
# hide @freelancers implementation details
def add_freelancer(f)
@freelancers.push(f)
end
# hide @clients implementation details
def add_client(c)
@clients.push(c)
end
end
Модификация Freelancer.initialize
Для метода initialize
теперь требуется объект MyDataStore
(с именем 'db').Недавно созданный объект Freelancer
добавляется в db
во время инициализации.
class Freelancer
attr_reader :name, :db, :skills, :clients
def initialize(name,db) # db is a new argument
@name = name
@skills = Array.new
@clients = Array.new
db.add_freelancer(self) # the new Freelancer is added to db
end
Аннотация над реализацией @skills и @clients
Пока мы думаем об этом, почему бы и нет?
#abstract over implementation
def add_skill(skill)
@skills.push(skill)
end
def add_client(client)
@clients.push(client)
end
end
Пример среды
Простое применение кода.Вместо того, чтобы называть каждый объект самостоятельно, мы просто сохраняем объект.В большинстве случаев это то, что мы хотим при создании.
db = MyDataStore.new
Freelancer.new('a', db)
Freelancer.new('b', db)
Freelancer.new('c', db)
Freelancer.new('d', db)
Freelancer.new('a', db)
Интерактив Обратите внимание, что db.freelancers
представляет собой совокупность объектов.Каждый объект уникально идентифицируется по хешу.Есть два разных фрилансера с именем 'a', и это не проблема (пока) .
Irb(main):10:0> db.freelancers
=> [#<Freelancer:0x00000001b1dd38 @clients=[], @name="a", @skills=[]>,
#<Freelancer:0x00000001b1dc98 @clients=[], @name="b", @skills=[]>,
#<Freelancer:0x00000001b1db30 @clients=[], @name="c", @skills=[]>,
#<Freelancer:0x00000001b1d9f0 @clients=[], @name="d", @skills=[]>,
#<Freelancer:0x00000001b1c988 @clients=[], @name="a", @skills=[]>]
Получение фрилансера по имени
Внимание: этокод зависит от деталей реализации. Это может быть скрыто
irb(main):907:0> db.freelancers.select {|f| f.name == 'a'}
=> [#<Freelancer:0x00000001b1dd38 @clients=[], @name="a", @skills=[]>,
#<Freelancer:0x00000001b1c988 @clients=[], @name="a", @skills=[]>]
Добавление навыка и клиента
Предупреждение: этот код опирается на детали реализации. Этотакже предполагается, что класс Client
был реализован.
# add @skill 'Ruby' to freelancer named 'b'
irb(main):10:0> db.freelancers.select {|f| f.name == 'b'}[0].add_skill('Ruby')
=> ["Ruby"]
# check freelancer named 'b' has skill 'Ruby'
irb(main):11:0> db.freelancers.select {|f| f.name == 'b'}
=> [#<Freelancer:0x00000001f16e58 @clients=[], @name="b", @skills=["Ruby"]>]
# uses '\' to span two lines for readability here on stackoverflow
irb(main):195:0> db.freelancers.select {|f| f.name == 'b'} \
[0].add_client(Client.new('Best Client', db))
=> [#<Client:0x00000001ed9af8 @name="Best Client", @skills=[]>]
#check that 'Best Client' has been added to db.clients
irb(main):196:0> db.clients
=> [#<Client:0x00000001ed9af8 @name="Best Client", @skills=[]>]
#check that 'Best Client' has been added to freelancer named 'b'
irb(main):197:0> db.freelancers.select {|f| f.name == 'b'} [0]
=> #<Freelancer:0x00000001e096f0 @name="b",
@skills=[],
@clients=[#<Client:0x00000001ed9af8 @name="Best Client", @skills=[]>]>
Обсуждение
Стоит подчеркнуть, мы всегда храним и передаем объекты и избегаем присвоения объектовпеременные, когда это возможно.Когда невозможно избежать назначения объекта переменной, мы стараемся сделать это временно в блоке, например {|f| f.name == 'b'}
.
- . Также важно подтвердить хранение данных.и поиск труден. И здесь мы проектируем наше собственное объектно-ориентированное хранилище данных .Существует масштаб, в котором это имеет смысл.
- Существуют приложения, в которых поддержание необходимой целостности данных с использованием внешней базы данных (SQLite, mySQL, Postgres) имеет больше смысла.