{"id":2511,"date":"2017-02-11T09:53:45","date_gmt":"2017-02-10T21:53:45","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2511"},"modified":"2017-02-11T11:20:29","modified_gmt":"2017-02-10T23:20:29","slug":"anonymous","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2511\/","title":{"rendered":"Anonymous Classes: Implementing Interfaces"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>A few years ago (2011 to be precise) <a href=\"http:\/\/stackoverflow.com\/questions\/6786401\/implement-a-delphi-interface-using-an-anonymous-class\">someone asked a question on StackOverflow about support for anonymous classes in Delph<\/a>i.  The reason for the question was that the poster was trying to use Delphi to develop for Android and on that platform the widespread use of callback interfaces makes anonymous classes <em>highly<\/em> desirable.<\/p>\n<p><!--more--><\/p>\n<p>As far as I know, despite oft repeated claims about how the Delphi language is &#8220;advancing&#8221;, Delphi <em>still<\/em> lacks this useful language feature.  Whilst there may be complex and contorted ways to contrive anonymity (as illustrated in the answer to that StackOverflow question) it is much more convenient to have the language support the ability to conjure an anonymous class as and when needed without having to provide all that scaffolding (or to be precise: to have the compiler take care of the scaffolding for you behind the scenes).<\/p>\n<p>Needless to say, Oxygene does this with aplomb (and did so even back in 2011).<\/p>\n<p>Let&#8217;s look at a very simple example: Connecting to a <a href=\"https:\/\/developers.google.com\/android\/reference\/com\/google\/android\/gms\/common\/api\/GoogleApiClient\">GoogleApiClient<\/a>.<\/p>\n<h2>GoogleApiClient.ConnectionCallbacks<\/h2>\n<p>As the hub for a wide range of Google Api&#8217;s this is a common task and connecting to the Api client involves handling a number of different callbacks.  All of these callbacks are provided to the Api client by supplying implementations of those callbacks as specified in interfaces.<\/p>\n<p>In our example scenario we have an activity which is connecting to the Api client (among other things) and it seems obvious at first to simply declare and implement the required callback interfaces directly on the activity itself:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\nMainActivity = public class(AppCompatActivity, View.OnClickListener,\r\n                                               OnMapReadyCallback, \r\n                                               GoogleApiClient.ConnectionCallbacks,\r\n                                               GoogleApiClient.OnConnectionFailedListener,\r\n                                               LocationListener,\r\n                                               ServiceConnection)\r\nprivate\r\n  fGoogleApis: GoogleApiClient;\r\npublic\r\n  method onCreate(savedInstanceState: Bundle); override;\r\n\r\n  \/\/ .. etc ..\r\n\r\npublic \/\/ -- Interfaces\r\n  \/\/ GoogleApiClient.ConnectionCallbacks\r\n  method onConnected(theHint: Bundle);\r\n  method onConnectionSuspended(theCause: Integer);\r\n\r\n  \/\/ GoogleApiClient.OnConnectionFailedListener\r\n  method onConnectionFailed(theResult: ConnectionResult); \r\nend;\r\n<\/pre>\n<p>This activity is not only providing callbacks for the Google Api Client but also for other things such as Google Maps notifications, Location Services updates, UI View click responses and even Service bindings.<\/p>\n<p>The broader details of all of these interfaces aren&#8217;t important, neither are the more general details of the <strong>MainActivity<\/strong> in this case.  What is important is that as we add more capabilities to our activity we can see how the number of interfaces being implemented can increase quite rapidly and, although it&#8217;s not shown, this also can result in a large number of methods on the activity, simply to satisfy those interfaces.<\/p>\n<p>In many cases the response to a particular callback is local to the point at which the callback is provided or simply provides a &#8220;hook&#8221; to respond to a callback to invoke more complex processing in our activity that is also invoked in other situations.<\/p>\n<p><strong>The result:<\/strong>  A great deal of noise in our activity, &#8216;polluting&#8217; the class and making it difficult to separate the real function of the activity from the scaffolding.<\/p>\n<p>Anonymous classes help us address that by avoiding the need to encumber the activity with these details.<\/p>\n<p>First, let&#8217;s back up a little and look at how we register the Api client callback interfaces when we configure our client, typically in the <strong>onCreate<\/strong> method of our activity:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n\r\n  method MainActivity.onCreate(savedInstanceState: Bundle);\r\n  begin\r\n    inherited onCreate(savedInstanceState);\r\n\r\n    \/\/ ..\r\n\r\n    fGoogleApis := new GoogleApiClient.Builder(self)\r\n      .addConnectionCallbacks(self)\r\n      .addOnConnectionFailedListener(self)\r\n      .addApi(Auth.GOOGLE_SIGN_IN_API, gso)\r\n      .addApi(LocationServices.API)\r\n      .build;\r\n\r\n    \/\/ ..    \r\n  end;\r\n\r\n<\/pre>\n<p>We use a <strong>GoogleApiClient<\/strong> builder to setup our Api client and register the <strong>MainActivity<\/strong> (<em>self<\/em>) as the provider of the connection callbacks.<\/p>\n<p>There are two separate callback interfaces involved here, but we&#8217;ll focus on the first (<strong>addConnectionCallbacks()<\/strong>)as this is the more complex of the two, requiring the implementation of two methods as opposed to just one.<\/p>\n<h2> An Anonmyous Class to Implement a Callback Interface <\/h2>\n<p>Instead of providing a reference to the <strong>MainActivity<\/strong> as the implementer of the <strong>GoogleApiClient.ConnectionCallbacks<\/strong> interface, we can provide an <em>inline<\/em> implementation of that interface without having to declare a formal class but using an anonymous class instead.<\/p>\n<p>The first step is to instantiate an anonymous class implementing the required interface.  We will use this in place of the reference to <em>self<\/em> when we registered the callbacks with <strong>addConnectionCallbacks<\/strong>.<\/p>\n<p>To instantiate an anonymous class we invoke <strong>new<\/strong> with the <strong>interface<\/strong> to identify the interface to be implemented on the anonymous class:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n\r\n    .addConnectionCallbacks(new interface GoogleApiClient.ConnectionCallbacks());\r\n\r\n<\/pre>\n<p>But of course we also need to provide an <em>implementation<\/em> for the interface.<\/p>\n<p>To do that we identify the implementation associated with each function by assigning a method body to the required interface member:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n\r\n    .addConnectionCallbacks\r\n    (\r\n      new interface GoogleApiClient.ConnectionCallbacks\r\n      (\r\n        onConnected := method(hint: Bundle)\r\n        begin\r\n          \/\/ What we do when we're connected to the Api client\r\n        end,\r\n\r\n        onConnectionSuspended := method(cause: Integer)\r\n        begin\r\n          \/\/ What we do when our Api client connection is suspended\r\n        end;\r\n      )\r\n    )\r\n\r\n<\/pre>\n<p>Obviously the way I have formatted the parenthesis blocks here is a purely personal preference.  You might prefer an alternate approach.<\/p>\n<p>This approach of assigning values (in this case method bodies) to members of a class directly in the constructor is not unique to anonymous classes.  It is the same pattern that is supported more generally in Oxygene to add in-line initialization of members on a new instance immediately following any required constructor parameters.<\/p>\n<p>In the case of anonymous classes of course there is only the default, parameterless constructor, so the additional initialization consists entirely of member method body assignments.<\/p>\n<h2> Cleaning Up the Activity <\/h2>\n<p>Having implemented the callbacks in this way we can now dramatically simplify our activity class:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\nMainActivity = public class(AppCompatActivity, View.OnClickListener,\r\n                                               OnMapReadyCallback,\r\n                                               LocationListener,\r\n                                               ServiceConnection)\r\nprivate\r\n  fGoogleApis: GoogleApiClient;\r\npublic\r\n  method onCreate(savedInstanceState: Bundle); override;\r\n\r\n  \/\/ .. etc ..\r\nend;\r\n<\/pre>\n<p>All that scaffolding to take care of implementing a few callbacks is swept away and obviously we could reduce it even further in this case if we took the same approach with those other callback interfaces still present.<\/p>\n<p>Which isn&#8217;t to say that you would <em>never<\/em> choose to implement a callback interface directly on an activity or other formal class type defined for the purpose.<\/p>\n<p>In some cases it might still make most sense to do so for a particular interface.  But with anonymous classes in your toolbox this becomes a deliberate <em>choice<\/em> rather than your only option.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>A few years ago (2011 to be precise) someone asked a question on StackOverflow about support for anonymous classes in Delphi. The reason for the question was that the poster was trying to use Delphi to develop for Android and on that platform the widespread use of callback interfaces makes anonymous classes highly desirable.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[212,205,4,180],"tags":[153,311,13,173],"class_list":["post-2511","post","type-post","status-publish","format-standard","hentry","category-android-2","category-cooper","category-delphi","category-oxygene","tag-android","tag-anonymous-classes","tag-language","tag-pascal"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-Ev","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2511","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=2511"}],"version-history":[{"count":10,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2511\/revisions"}],"predecessor-version":[{"id":2521,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2511\/revisions\/2521"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2511"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2511"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}