430 likes | 444 Views
Learn how to define software objects and their collaborations using Design Class Diagrams (DCDs) in object-oriented design. DCDs provide an abstract and visual representation of relationships among classes in OO programs, helping you reason about and improve the design. This article focuses on using DCDs for Rails models, showcasing their features and conventions.
E N D
https://flic.kr/p/9iZYNC Design Class Diagrams
Object-Oriented Design “Define software objects and how they collaborate to satisfy their requirements” • Ability to reason about design important! • Understand designer’s intent • Critique/improve the design
Source code not best medium for reasoning • Lots of redundancy and irrelevant detail • Poor at depicting relationships among classes in OO programs Solution: Use abstract, visual representations—for example, Design Class Diagrams (DCDs)
Overview • Previously: Domain class diagrams • Model problem domain • Today: Design class diagrams • Model Rails model (as in MVC) classes • Also model other software classes (e.g., controller)
Design Class Diagrams for Rails Models • Observation: Rails model classes somewhat limited in expressiveness • Thus: Subset of class diagram notation sufficient • Plus a few Rails-model-specific conventions
Features of Rails Model • Classes • Attributes • Associations
Features of Rails Model • Classes • Attributes • Associations
How to model/code a User class and a Sale class?
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string How to model/code a User class and a Sale class? # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string Commands to generate classes: $ rails generate model User $ rails g model Sale # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string No need to model base class # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end Sale price : integer description : string
Features of Rails Model • Classes • Attributes • Associations
Rails Model Attribute Types • :string • :integer • :float • :decimal • :boolean • :primary_key • :text • :binary • :datetime • :timestamp • :time • :date Taken from http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string How to model/code User’s name and email, and Sale’s price and description attributes? # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string How to generate attributes: $ rails g migration add_basic_info_to_users \ name:string email:string $ rails g migration add_basic_info_to_sales \ price:integer description:string # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string Model attributes defined by database migrations (colons part of symbol) # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string Attribute Type Attribute name Colon separator # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end Sale price : integer description : string
Features of Rails Model • Classes • Attributes • Associations
Rails Model Class Associations • One-to-one:has_one / belongs_to • One-to-many:has_many / belongs_to • Many-to-many: has_and_belongs_to_many Taken from http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Class Diagram for has_one Employee Office Has 1 1 employee office
Class Diagram for has_one Employee Office Has 1 1 employee office
Class Diagram for has_many Manager Employee Has 1 * manager employee
Class Diagram for has_many Manager Employee Has 1 * manager employee singular by UMLconvention
Class Diagram for has_and_belongs_to_many Programmer Project Has * * programmer project
Class Diagram for has_and_belongs_to_many Programmer Project Has * * programmer project Directionunspecified
Short/Long Form for Rails Model Associations Short form: class Manager < ActiveRecord::Base has_many:employees, :class_name => Employee, :foreign_key => manager_id end class Employee < ActiveRecord::Base belongs_to:manager, :class_name => Manager, :foreign_key => manager_id end Long form:
Short/Long Form for Rails Model Associations Short form: class Manager < ActiveRecord::Base has_many:employees, :class_name => Employee, :foreign_key => manager_id end class Employee < ActiveRecord::Base belongs_to:manager, :class_name => Manager, :foreign_key => manager_id end Long form: Customizable
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string How to model/code each User “buyer” has many Sale “purchases”? # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string buyer 1 Has # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end purchase * Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string buyer 1 Has # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end purchase * Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string buyer 1 How to model/code each User “seller” has many “sales”? Has # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end purchase * Sale price : integer description : string
# name :string # email :string class User < ActiveRecord::Base has_many :purchases, :class_name => 'Sale’, :foreign_key => 'buyer_id' has_many :sales, :class_name => 'Sale’, :foreign_key => 'seller_id' end User name : string email : string buyer 1 seller 1 Has Has # price :integer # description :string class Sale < ActiveRecord::Base belongs_to :buyer, :class_name => 'User’, :foreign_key => 'buyer_id' belongs_to :seller, :class_name => 'User’, :foreign_key => 'seller_id’ end purchase sale * * Sale price : integer description : string
UsersController Example UsersController +show() +new() +create() -user_params() : User[*] -@user 1 User
Methods UsersController +show() +new() +create() -user_params() : User[*] -@user 1 User
Return Type UsersController +show() +new() +create() -user_params() : User[*] 0 or more -@user 1 User
Instance Variable UsersController +show() +new() +create() -user_params() : User[*] -@user 1 User
Reference to Class Instance UsersController +show() +new() +create() -user_params() : User[*] -@user 1 User
Visibility UsersController +show() +new() +create() -user_params() : User[*] + public - private # protected -@user 1 User
With these notations, you should be able to express the structure of your object-oriented designsNext time, we’ll cover behavior UsersController +show() +new() +create() -user_params() : User[*] -@user 1 User
A word about agile modeling(quoting Larman) Experienced analysts and modelers know thesecret of modeling: Thus, we favor hand-drawn diagrams over typeset ones The purpose of modeling (sketching UML, …) is primarily to understand, not to document. http://flic.kr/p/7SFKjj
Tip: Sketch classes starting from the upper left Sale Payment Store address
UML class diagrams have even more notations • Two good references: