Rick

Rick
Rick

Friday, January 18, 2013

Java Developer Guide to Go Programming Collections Article 5

Go programming is strongly typed like Java, C and C++, but has built-in collection support like Python, and Ruby. Lists (growable arrays) in Go programming are called slices. Dictionary aka associative arrays (aka JavaScript objects like things) are called maps (just like the name java.util.Map).
To demonstrate collection usage and a few other language constructs, I added a Department that has a list of employees. I also threw in a few maps for good measure. What follows is Java with the functional equivalents in Go Programming....
First I show in Java and then you use your knowledge of Java and some labels/comments I added to see the equivalent in GO

Java Department class

package com.example.collections;

import java.util.ArrayList;
import java.util.List;

public class Department {
 
 private List employees = new ArrayList<>();
 private String name;
  
 public Department(String name, Employee... employees) {
  this.name = name;  
  for (Employee employee : employees) {
   this.employees.add(employee);
  }
 }


 public List getEmployees() {
  return employees;
 }
 public void setEmployees(List employees) {
  this.employees = employees;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 
 

}

Go Department class

package collections

type Department struct {
 name      string
 employees [] Employee
}

func NewDepartment(name string, employees ...Employee) *Department {
 return &Department{name, employees}
}

func (this *Department) Name() string {
 return this.name
}

func (this *Department) SetName(name string) {
 this.name = name
}

func (this *Department) Employees() []Employee {
 return this.employees
}

func (this *Department) SetEmployees(employees []Employee) {
 this.employees = employees
}

Now a new Company class to do some operations and construction of departments.
Now a new Company class to do some operations and construction of departments.

Java Company class

package com.example.collections;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Company {
 
 // (A) Create a map to hold employee id to hours worked this quarter
 private static Map empIdToHoursWorked = new HashMap<>();
 // (B) Create a map to hold employee id to sales this quarter
 private static Map empIdToSales = new HashMap<>();
 // (B.1) list of departments
 private static List departments = new ArrayList<>();
 // (B.2) map of department names to departments
 private static Map deptNameToDepartment = new HashMap<>();

 
 static {
  //(C) declare four departments
  Department sales =new Department("sales", new SalesEmployee(3L, "Whitney", "Hightower", 17,true, 0.05),
    new SalesEmployee(60L, "Alexander", "Hightower", 17,true, 0.05));
  


  Department engineering =new Department("engineering", 
        new Employee(1L, "Rick", "Hightower", 32, true), 
        new HourlyEmployee(2L, "Bob", "Hightower", 27, true, 25.0));



  Department hr =new Department("hr", 
    new Employee(10L, "Diana", "Hightower", 32, true), 
    new HourlyEmployee(20L, "Martha", "Hightower", 27, true, 25.0),
    new HourlyEmployee(30L, "Daniella", "Hightower", 27, true, 25.0));
  
  
  Department manufacturing =new Department("manufacturing", 
    new Employee(40L, "Joeseph", "Hightower", 32, true), 
    new HourlyEmployee(50L, "John", "Hightower", 27, true, 25.0));

  
  // (D) Bob worked 1750 hours this quarter. Martha and Daneilla each worked 350. How many did John work?
  empIdToHoursWorked.put(2L, 1750.0);
  empIdToHoursWorked.put(30L, 350.0);
  empIdToHoursWorked.put(20L, 350.0);
  empIdToHoursWorked.put(50L, 350.0);
  
  // (E) Whitney is our best sales person, but Alexander did good for a three year old.
  empIdToSales.put(60L, 5_000_000.0);
  empIdToSales.put(3L, 1_000_000.0);
  

  
  // (F) Add the three departments to the list of departments
  departments.add(engineering);
  departments.add(hr);
  departments.add(manufacturing);
  departments.add(sales);
  
  // (G) add some department to name mappings
  deptNameToDepartment.put(engineering.getName(), engineering);
  deptNameToDepartment.put(hr.getName(), hr);
  deptNameToDepartment.put(manufacturing.getName(), manufacturing);
  deptNameToDepartment.put(sales.getName(), sales);


 }
 
 // (H) Calculate Employee Cost
 public static double calculateCompanyEmployeeCost () {
  
  double totalCost = 0.0;
  //Nested for loop, looping over employees in each department.
  for (Department department : departments) {
   for (Employee employee : department.getEmployees()) {
    if (employee instanceof SalesEmployee) {
     ((SalesEmployee) employee).setQuarterlySales(empIdToSales.get(employee.getId()));
    } else if (employee instanceof HourlyEmployee) {
     ((HourlyEmployee) employee).setHoursWorkedThisQuarter(empIdToHoursWorked.get(employee.getId()));
    }
    totalCost += employee.calculatePay();
   }
  }
  
  return totalCost;
 }

}

Go Company Module

package collections

var (
 // (A) Create a map to hold employee id to hours worked this quarter
 empIdToHoursWorked map[int64]float64 = make(map[int64]float64)
 // (B) Create a map to hold employee id to sales this quarter
 empIdToSales map[int64]float64 = make(map[int64]float64)
 // (B.1) list of departments
 departments []*Department = make([]*Department, 0, 10)
 // (B.2) map of department names to departments
 deptNameToDepartment map[string]*Department = make(map[string]*Department)
)

func init() {
 //(C) declare four departments
 sales := NewDepartment("sales", NewSalesEmployee(3, "Whitney", "Hightower", 17, true, 0.05),
  NewSalesEmployee(60, "Alexander", "Hightower", 17, true, 0.05))

 engineering := NewDepartment("engineering",
  NewEmployee(1, "Rick", "Hightower", 32, true),
  NewHourlyEmployee(2, "Bob", "Hightower", 27, true, 25.0))

 hr := NewDepartment("hr",
  NewEmployee(10, "Diana", "Hightower", 32, true),
  NewHourlyEmployee(20, "Martha", "Hightower", 27, true, 25.0),
  NewHourlyEmployee(30, "Daniella", "Hightower", 27, true, 25.0))

 manufacturing := NewDepartment("manufacturing",
  NewEmployee(40, "Joeseph", "Hightower", 32, true),
  NewHourlyEmployee(50, "John", "Hightower", 27, true, 25.0))

 // (D) Bob worked 1750 hours this quarter. Martha and Daneilla each worked 350. How many did John work?
 empIdToHoursWorked[2] = 1750.0
 empIdToHoursWorked[30] = 350.0
 empIdToHoursWorked[20] = 350.0
 empIdToHoursWorked[50] = 350.0

 // (E) Whitney is our best sales person, but Alexander did good for a three year old.
 empIdToSales[60] = 5000000
 empIdToSales[3] = 1000000

 // (F) Add the three departments to the list of departments
 departments = append(departments, engineering, hr, manufacturing, sales)

 // (G) add some department to name mappings
 deptNameToDepartment[engineering.Name()] = engineering
 deptNameToDepartment[hr.Name()] = hr
 deptNameToDepartment[manufacturing.Name()] = manufacturing
 deptNameToDepartment[sales.Name()] = sales

}

// (H) Calculate Employee Cost
func CalculateCompanyEmployeeCost() float64 {

 totalCost := 0.0
 //Nested for loop, looping over employees in each department.
 for _, department := range departments {
  for _, employee := range department.Employees() {
   switch employee.(type) {
   case SalesEmployee:
    employee.(SalesEmployee).SetQuarterlySales(empIdToSales[employee.Id()])
   case HourlyEmployee:
    employee.(HourlyEmployee).SetHoursWorkedThisQuarter(empIdToHoursWorked[employee.Id()])
   }
   totalCost += employee.CalculatePay()
  }
 }
 return totalCost

}

Now the employees

Java Employees

package com.example.collections;

public class Employee  {
 
 protected long id;
 protected String firstName;
 protected String lastName;
 protected int age;
 protected boolean current;
 
 
 
 public Employee(long id, String firstName, String lastName, int age, boolean current) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
  this.current = current;
  this.id = id;
 }
 
 public double calculatePay()  {
  return 0.0d;
 }
 
 public String name() {
  return this.firstName + " " + this.lastName;
 }


 public String getFirstName() {
  return firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public int getAge() {
  return age;
 }

 public long getId() {
  return id;
 }

 public boolean isCurrent() {
  return current;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public void setCurrent(boolean current) {
  this.current = current;
 }

}

package com.example.collections;

public class HourlyEmployee extends Employee {

 private double hourlyRate;
 private transient double hoursWorkedThisQuarter;



 public HourlyEmployee(Long id, String firstName, String lastName, int age,
   boolean current, double commisionRate) {
  super(id, firstName, lastName, age, current);
  this.hourlyRate = commisionRate;
 }
 
 public double calculatePay()  {
  return this.hourlyRate * hoursWorkedThisQuarter; //lookup hours worked in DB, but for this just hard code
 }


 public double getHourlyRate() {
  return hourlyRate;
 }

 public void setHourlyRate(double hourlyRate) {
  this.hourlyRate = hourlyRate;
 }

 public void setHoursWorkedThisQuarter(double hoursWorkedThisQuarter) {
  this.hoursWorkedThisQuarter = hoursWorkedThisQuarter;
 }


}

package com.example.collections;

public class SalesEmployee extends Employee {

 private double commisionRate;
 private transient double quarterlySales = -1;


 public SalesEmployee(Long id, String firstName, String lastName, int age,
   boolean current, double commisionRate) {
  super(id, firstName, lastName, age, current);
  this.commisionRate = commisionRate;
 }
 
 public double calculatePay()  {
  if (quarterlySales == -1) {
   throw new RuntimeException("quarterly sales not set");
  }
  return this.commisionRate * quarterlySales; 
 }


 public double getCommisionRate() {
  return commisionRate;
 }

 public void setCommisionRate(double commisionRate) {
  this.commisionRate = commisionRate;
 }
 
 public void setQuarterlySales(double sales) {
  this.quarterlySales = sales;
 }


}


Now the Go Employees
package collections

type Employee interface {
  CalculatePay() float64
  Name() string
  Id() int64
}

type EmployeeImpl struct {
 id   int64
 firstName string
 lastName  string
 age       int
 current   bool
}

func (this *EmployeeImpl) CalculatePay() float64 {
 return 0.0
}

func (this *EmployeeImpl) Name() string {
 return this.firstName + " " + this.lastName
}


func NewEmployee(id int64, firstName string, lastName string, age int, current bool) *EmployeeImpl {
 return &EmployeeImpl{id, firstName, lastName, age, current}
}

func (this *EmployeeImpl) FirstName() string {
 return this.firstName
}

func (this *EmployeeImpl) LastName() string {
 return this.lastName
}

func (this *EmployeeImpl) Age() int {
 return this.age
}

func (this *EmployeeImpl) Id() int64 {
 return this.id
}


func (this *EmployeeImpl) Current() bool {
 return this.current
}

func (this *EmployeeImpl) SetFirstName(name string) {
 this.firstName = name
}

func (this *EmployeeImpl) SetLastName(name string) {
 this.lastName = name
}

func (this *EmployeeImpl) SetAge(newAge int) {
 this.age = newAge
}

func (this *EmployeeImpl) SetCurrent(current bool) {
 this.current = current
}


func (this *SalesEmployeeImpl) SetHoursWorkedThisQuarter(sales float64) {
 this.quarterlySales = sales
}


package collections


type HourlyEmployee interface {
 Employee
 SetHoursWorkedThisQuarter(rate float64)
}

type HourlyEmployeeImpl struct {
 EmployeeImpl //HourlyEmployee extends Employee by using this anonymous field
 hourlyRate float64
 hoursThisQuarter float64
 
}

func NewHourlyEmployee(id int64, firstName string, lastName string, age int, current bool, 
      hourlyRate float64) *HourlyEmployeeImpl {
 return &HourlyEmployeeImpl{EmployeeImpl{id, firstName, lastName, age, current}, hourlyRate, 0.0}
}

func (this *HourlyEmployeeImpl) CalculatePay() float64 {
 return this.hourlyRate * this.hoursThisQuarter
}


func (this *HourlyEmployeeImpl) HourlyRate() float64 {
 return this.hourlyRate
}

func (this *HourlyEmployeeImpl) SetHourlyRate(rate float64) {
 this.hourlyRate = rate
}


func (this *HourlyEmployeeImpl) SetHoursWorkedThisQuarter(rate float64) {
 this.hoursThisQuarter = rate
}
package collections


type SalesEmployee interface {
 Employee
 SetQuarterlySales(rate float64)
}

type SalesEmployeeImpl struct {
 EmployeeImpl //Sales extends Employee by using this anonymous field
 commisionRate float64
 quarterlySales float64
 
}

func (this *SalesEmployeeImpl) CalculatePay() float64 {
 return this.commisionRate * this.quarterlySales
}

func NewSalesEmployee(id int64, firstName string, lastName string, age int, current bool, commisionRate float64) *SalesEmployeeImpl {
 return &SalesEmployeeImpl{EmployeeImpl{id, firstName, lastName, age, current}, commisionRate, 0.0}

}

func (this *SalesEmployeeImpl) CommisionRate() float64 {
 return this.commisionRate
}

func (this *SalesEmployeeImpl) SetCommisionRate(rate float64) {
 this.commisionRate = rate
}

func (this *SalesEmployeeImpl) SetQuarterlySales(sales float64) {
 this.quarterlySales = sales
}

Now the main method that call them both.

In Java...

package com.example;

import com.example.collections.Company;

public class UseCollection {
 
 public static void main(String[] args) {
  
  System.out.printf("Money spent on employees for last quarter %2.2f \n", Company.calculateCompanyEmployeeCost());

 }

}

In Go...

package main

import (
 "example/collections"
 "fmt"
)

func main() {

  fmt.Printf("Money spent on employees for last quarter %2.2f \n", collections.CalculateCompanyEmployeeCost());


}


Kafka and Cassandra support, training for AWS EC2 Cassandra 3.0 Training