Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

Rails for Java Developers phần 4 ppt
Nội dung xem thử
Mô tả chi tiết
MIXINS 91
def add_employee(employee)
employee.employer.remove_employee(employee) if employee.employer
self.employees << employee
employee.employer = self
end
def remove_employee(employee)
self.employees.delete employee
employee.employer = nil
end
end
Classes such as BusinessPerson can then pick up Employer functionality
by calling include Employer:
Download code/rails_xt/samples/business_person.rb
class BusinessPerson < Person
include Employer, Employee
end
Now the BusinessPerson class can call any Employer methods:
irb(main):001:0> require 'business_person'
=> true
irb(main):002:0> boss = BusinessPerson.new("Justin", "Gehtland")
=> #<BusinessPerson:0x54394 @first_name="Justin", @last_name="Gehtland">
irb(main):003:0> drone = BusinessPerson.new("Stu", "Halloway")
=> #<BusinessPerson:0x4f9d4 @first_name="Stu", @last_name="Halloway">
irb(main):004:0> boss.add_employee(drone)
=> etc.
The fact that include is a method call has interesting implications. The
object model is not static, and you could choose to have BusinessPerson
include Employer under some circumstances and not others. In fact,
you can make object model decisions per instance instead of per class.
The extend method works like include but on a specific instance. So, a
specific person could become an Employer at runtime:
irb(main):001:0> require 'business_person'
=> true
irb(main):002:0> p = Person.new("Stu", "Halloway")
=> #<Person:0x5490c @first_name="Stu", @last_name="Halloway">
irb(main):003:0> class <<p; ancestors; end
=> [Person, Object, Kernel]
irb(main):004:0> p.extend Employer
=> #<Person:0x5490c @first_name="Stu", @last_name="Halloway">
irb(main):005:0> class <<p; ancestors; end
=> [Employer, Person, Object, Kernel]
The variable p starts life as a “plain old Person” with class ancestors
[Person, Object, Kernel]. The extend Employer call turns p into an Employer
as well, and the ancestor list changes appropriately. The odd-looking
FUNCTIONS 92
statement class <<p accesses the singleton class of p. A singleton class singleton class
might better be known as an instance-specific class. You have modified
the inheritance hierarchy of p, so it is not “just a Person.” It now has its
own instance-specific class, which tracks its unique ancestors list.
3.9 Functions
Strictly speaking, neither Java nor Ruby has functions. Nevertheless,
it is reasonable to talk about functions: Sometimes a function can be
handy, and both Java and Ruby have important idioms for these situations. Consider this simple example, a program that reads a bunch of
lines from stdin and then prints them back sorted:
Download code/java_xt/src/SortWords.java
import java.io.*;
import java.util.*;
public class SortWords {
public static void main(String[] args)
throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
List al = new ArrayList();
String line = null;
while (null != (line = br.readLine())) {
al.add(line);
}
Collections.sort(al);
System.out.println("sorted:");
for (Iterator it = al.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
}
Here is an equivalent program in Ruby:
Download code/rails_xt/samples/sort_words.rb
puts readlines.sort.unshift("sorted:\n").join
Both programs produce output like this:
$ ruby samples/sort_words.rb
quick
brown
fox (close stdin here with Ctrl-D or equivalent...)
sorted:
brown
fox
quick
FUNCTIONS 93
Fine so far. But what if you wanted to sort by some other criteria, such
as word length or preponderance of vowels? If you can imagine lots of
different criteria, or if new criteria might turn up at runtime, you will
quickly want a general solution that might look like this:
Collections.sort(al, sortByWordLength);
In English, this might read as “Sort the collection al using the function
sortByWordLength( ) to compare words.” And, in fact, Java works exactly
like this—except without the f-word.4
Instead of using a function, you
can build a function-like object out of pieces you do have: interfaces
and inheritance. Java’s collections API provides a Comparator interface:
public interface Comparator {
int compare(Object o, Object o1);
}
You can write your own class that implements Comparator and compares strings by some criteria you care about. Return a negative number if the first object is lesser, 0 if the objects are equal, and a positive
number if the second object is the lesser of the two. Creating an entirely
new class just to specify a sort order is often a big diversion, so Java
provides a shortcut called the anonymous inner class. Using an anonymous inner class, you can specify the sort “function” directly inside the
call to sort:
Download code/java_xt/src/SortWords2.java
Collections.sort(al, new Comparator() {
public int compare(Object o, Object o1) {
return ((String)o).length() - ((String)o1).length();
}
});
Java’s anonymous inner classes, when used in this way, are functions
in everything but name. Having an ordering function return negative, 0,
or positive is common to Java and Ruby (and many other languages).
In Ruby, you can use a block to implement the sort “function”:
Download code/rails_xt/samples/sort_words_2.rb
sorted = readlines.sort {|x,y| x.length-y.length}
puts "sorted:\n#{sorted.join}"
The block syntax (curly braces or do...end) is the same syntax you examined in Section 2.4, Collections and Iteration, on page 47. In Ruby, you
will typically use a block whenever you want to “pass a function to a
4. The seven-letter f-word. Shame on you.