Evolutionary architecture and emergent design

Source: Internet
Author: User
Tags split wrapper

In this column last month, I covered an example of using a specific domain language (DSL), defined in your code as a common design practice. (I introduced the concept of idiomatic patterns in the "combining methods and SLAP" article.) DSL is a good medium for capturing patterns because they are declarative, easier to read than "normal" source code, and make your capture patterns stand out from the surrounding code.

The language technology used to build a DSL is often an ingenious way to implicitly provide a wrapper context for your code. In other words, DSLs try to "hide" the messy syntax using the potential language features to make your code more readable. Although you can build DSLs using the Java language, DSLs are used to hide the poor constructs of contexts, and their rigid and impermanent syntax, making them unsuitable for this technique. But other JVM-based languages can fill this void. In this and the next installment, I'll show you how to extend your DSL build palette, which contains more expressive languages that run on the Java platform, starting with Groovy.

Groovy offers a variety of features that make it easier to build a DSL, and the number of support in a DSL is a common requirement. People always need a lot of numbers: 7 inches, 4 miles, 13 days. Groovy allows you to add support for numbers directly through an open class. Open source classes allow you to reopen an existing class and modify it by adding, deleting, or modifying methods in the class-a powerful but dangerous mechanism. Fortunately, there is a safe way to accomplish this. Groovy supports two different types of open class syntax: Categories and Expandometaclass.

Open Class via Categories

The concept of categories is borrowed from the Smalltalk and Objective-c languages. A categories can create a wrapper around a code call that contains one or more open classes, using the use block directive.

A better understanding of the categories concept through an example. Listing 1 shows a test of the new Method Camelize () that I have added to string, which converts an underlined string to camel-case:

Listing 1. Test demo camelize () method

class TestStringCategory extends GroovyTestCase {
   def expected = ["event_map" : "eventMap",
       "name" : "name", "test_date" : "testDate",
       "test_string_with_lots_of_breaks" : "testStringWithLotsOfBreaks",
       "String_that_has_init_cap" : "stringThatHasInitCap" ]

   void test_Camelize() {
     use (StringCategory) {
       expected.each { key, value ->
         assertEquals value, key.camelize()
       }
     }
   }
}

In Listing 1, I created a expected hash value using the original and converted cases, and then stringcategory each keyword in terms of the mapped iteration wrapper (camelized). Note that in the use block, you do not need to do anything special to invoke the new method in the class.

The Stringcategory code is shown in Listing 2:

Listing 2. Stringcategory class

class StringCategory {

  static String camelize(String self) {
   def newName = self.split("_").collect() {
    it.substring(0, 1).toUpperCase() + it.substring(1, it.length())
   }.join()
   newName.substring(0, 1).toLowerCase() + newName.substring(1, newName.length())
  }
}

Categories is a general class that contains static methods. A static method must have a parameter, which is the type you want to add. In Listing 2, I declare a separate static method that receives the String parameter (usually called self, but you can name it at will), representing the class to which I added the method. The method body contains Groovy code, which divides the string into delimited chunks (this is what the split ("_") method does), and then collects the strings together and uses uppercase letters to stitch them up in the right place. The last line ensures that the first character returned is lowercase.

When you are using Stringcategory, you must access it in the use block. It is legal to have more than one categories class in the parentheses of the use block, separated by commas.

This is another example of using open classes in a DSL to represent quantities, taking into account the code in Listing 3, which implements an appointment calendar:

Listing 3. A simple calendar DSL

def calendar = new AppointmentCalendar()

use (IntegerWithTimeSupport) {
   calendar.add new Appointment("Dentist").from(4.pm)
   calendar.add new Appointment("Conference call")
          .from(5.pm)
          .to(6.pm)
          .at("555-123-4321")
}
calendar.print()

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.