SlideShare ist ein Scribd-Unternehmen logo
1 von 58
Downloaden Sie, um offline zu lesen
Apex Design Patterns
Developers
Dennis Thong
Senior Technical Solution Architect


Richard Vanhook
Senior Technical Solution Architect
Safe Harbor
 Safe harbor statement under the Private Securities Litigation Reform Act of 1995:

 This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if
 any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-
 looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of
 product or service availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of
 management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments
 and customer contracts or use of our services.

 The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our
 service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth,
 interruptions or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and other litigation, risks associated
 with possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain,
 and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling
 non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the
 financial results of salesforce.com, inc. is included in our annual report on Form 10-Q for the most recent fiscal quarter ended July 31, 2012. This
 documents and others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site.

 Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may
 not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently
 available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
The Plan
 Cover six design patterns
   Problem
   Pattern Abstract
   Code
 Your participation is encouraged!
Patterns
1. ?
2. ?
3. ?
4. ?
5. ?
6. ?
Meet Billy, Your Admin

             • 3+ yrs as Salesforce Admin
             • Just recently started coding
             • Sad because of this:
                Trigger.AccountTrigger: line 3, column 1
                System.LimitException: Too many record
                type describes: 101



             • Needs your help!
The Offending Code
01   trigger AccountTrigger on Account (before insert, before update) {
02       for(Account record : Trigger.new){
03           AccountFooRecordType rt = new AccountFooRecordType();
04           ....
05       }
06   }

07   public class AccountFooRecordType {
08       public String id {get;private set;}
09       public AccountFooRecordType(){
10           id = Account.sObjectType.getDescribe()
11               .getRecordTypeInfosByName().get('Foo').getRecordTypeId();
12       }
13   }



       • When a single Account is inserted, what happens?
       • When 200+ Accounts are inserted…?
Solution: Singleton




                                 Singleton

                      - instance : Singleton

                      - Singleton()
                      + getInstance() : Singleton
Let’s Code It!
 01   trigger AccountTrigger on Account (before insert, before update) {
 02       for(Account record : Trigger.new){
 03           AccountFooRecordType rt = new AccountFooRecordType();
 04           ....
 05       }
 06   }

 07   public class AccountFooRecordType {
 08       public String id {get;private set;}
 09       public AccountFooRecordType(){
 10           id = Account.sObjectType.getDescribe()
 11               .getRecordTypeInfosByName().get('Foo').getRecordTypeId();
 12       }
 13   }



      • Above is the offending code again
      • Changes are highlighted in next slides
Let’s Code It!
 01   trigger AccountTrigger on Account (before insert, before update) {
 02       for(Account record : Trigger.new){
 03           AccountFooRecordType rt = (new AccountFooRecordType()).getInstance();
 04           ....
 05       }
 06   }

 07   public class AccountFooRecordType {
 08       public String id {get;private set;}
 09       public AccountFooRecordType(){
 10           id = Account.sObjectType.getDescribe()
 11               .getRecordTypeInfosByName().get('Foo').getRecordTypeId();
 12       }
 13       public AccountFooRecordType getInstance(){
 14          return new AccountFooRecordType();
 15       }
 16   }
Let’s Code It!
 01   trigger AccountTrigger on Account (before insert, before update) {
 02       for(Account record : Trigger.new){
 03           AccountFooRecordType rt = AccountFooRecordType.getInstance();
 04           ....
 05       }
 06   }

 07   public class AccountFooRecordType {
 08       public String id {get;private set;}
 09       public AccountFooRecordType(){
 10           id = Account.sObjectType.getDescribe()
 11               .getRecordTypeInfosByName().get('Foo').getRecordTypeId();
 12       }
 13       public static AccountFooRecordType getInstance(){
 14          return new AccountFooRecordType();
 15       }
 16   }
Static

 • Can modify member variables, methods, and blocks
 • Executed when?
    • When class is introduced (loaded) to runtime environment
 • How long does that last in Java?
    • Life of the JVM
 • In Apex?
    • Life of the transaction
Let’s Code It!
 01   trigger AccountTrigger on Account (before insert, before update) {
 02       for(Account record : Trigger.new){
 03           AccountFooRecordType rt = AccountFooRecordType.getInstance();
 04           ....
 05       }
 06   }

 07   public class AccountFooRecordType {
 08       public String id {get;private set;}
 09       public AccountFooRecordType(){
 10           id = Account.sObjectType.getDescribe()
 11               .getRecordTypeInfosByName().get('Foo').getRecordTypeId();
 12       }
 13       public static AccountFooRecordType getInstance(){
 14          return new AccountFooRecordType();
 15       }
 16   }
Let’s Code It!
 01   trigger AccountTrigger on Account (before insert, before update) {
 02       for(Account record : Trigger.new){
 03           AccountFooRecordType rt = AccountFooRecordType.getInstance();
 04           ....
 05       }
 06   }

 07   public class AccountFooRecordType {
 08       public static AccountFooRecordType instance = null;
 09       public String id {get;private set;}
 10       public AccountFooRecordType(){
 11           id = Account.sObjectType.getDescribe()
 12               .getRecordTypeInfosByName().get('Foo').getRecordTypeId();
 13       }
 14       public static AccountFooRecordType getInstance(){
 15           if(instance == null) instance = new AccountFooRecordType();
 16           return instance;
 17       }
 18   }
Let’s Code It!
 01   trigger AccountTrigger on Account (before insert, before update) {
 02       for(Account record : Trigger.new){
 03           AccountFooRecordType rt = AccountFooRecordType.getInstance();
 04           ....
 05       }
 06   }

 07   public class AccountFooRecordType {
 08       private static AccountFooRecordType instance = null;
 09       public String id {get;private set;}
 10       public AccountFooRecordType(){
 11           id = Account.sObjectType.getDescribe()
 12               .getRecordTypeInfosByName().get('Foo').getRecordTypeId();
 13       }
 14       public static AccountFooRecordType getInstance(){
 15           if(instance == null) instance = new AccountFooRecordType();
 16           return instance;
 17       }
 18   }
Let’s Code It!
 01   trigger AccountTrigger on Account (before insert, before update) {
 02       for(Account record : Trigger.new){
 03           AccountFooRecordType rt = AccountFooRecordType.getInstance();
 04           ....
 05       }
 06   }

 07   public class AccountFooRecordType {
 08       private static AccountFooRecordType instance = null;
 09       public String id {get;private set;}
 10       private AccountFooRecordType(){
 11           id = Account.sObjectType.getDescribe()
 12               .getRecordTypeInfosByName().get('Foo').getRecordTypeId();
 13       }
 14       public static AccountFooRecordType getInstance(){
 15           if(instance == null) instance = new AccountFooRecordType();
 16           return instance;
 17       }
 18   }
Patterns
1. Singleton
2. ?
3. ?
4. ?
5. ?
6. ?
geocode('moscone center')
//=> 37.7845935,-122.3994262
Your Suggestion to Billy
 01   public class GoogleMapsGeocoder{
 02       public static List<Double> getLatLong(String address){
 03           //web service callout of some sort
 04           return new List<Double>{0,0};
 05       }
 06   }

 07   System.debug(GoogleMapsGeocoder.getLatLong('moscone center'));
 08   //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0)




       But then Billy mentions these requirements
        Need other options besides Google Maps
        Allow client code to choose provider
Solution: Strategy

                                         Context            strategies           Strategy
                Client
                                    +operation()        1                    +operation()
                                                                         *
  defines a family of algorithms,
                                                        ConcreteStrategyA                        ConcreteStrategyB
  encapsulates each one, and makes
                                                   +operation()                             +operation()
  them interchangeable
   Context => Geocoder
   operation() => getLatLong()
   Strategy => GeocodeService
   ConcreteStrategyA => GoogleMapsImpl
   ConcreteStrategyB => MapQuestImpl
Let’s Code It!
 01   public interface GeocodeService{
 02       List<Double> getLatLong(String address);
 03   }


 04   public class GoogleMapsImpl implements GeocodeService{
 05       public List<Double> getLatLong(String address){
 06           return new List<Double>{0,0};
 07       }
 08   }


 09   public class MapQuestImpl implements GeocodeService{
 10       public List<Double> getLatLong(String address){
 11           return new List<Double>{1,1};
 12       }
 13   }
01   public class Geocoder {
02       private GeocodeService strategy;
03       public Geocoder(GeocodeService s){
04          strategy = s;
05       }
06       public List<Double> getLatLong(String address){
07          return strategy.getLatLong(address);
08       }
09   }

                                           Geocoder
                                                             strategies                 GeocodeService
             Client         + Geocoder(GeocodeService)
                                                         1                       +getLatLong(String)
                            +getLatLong(String)                           *

                                                                      GoogleMapsImpl                           MapQuestImpl

                                                               +getLatLong(String)                     +getLatLong(String)


10   Geocoder geocoder = new Geocoder(new GoogleMapsImpl());
11   System.debug(geocoder.getLatLong('moscone center'));
12   //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0)
01   public class Geocoder {
02       public static final Map<String,Strategy> strategies = new
03           Map<String,Strategy>{'googlemaps' => new GoogleMapsImpl()
04                               ,'mapquest'   => new MapQuestImpl()};
05       private GeocodeService strategy;
06       public Geocoder(String name){ strategy = strategies.get(name);}
07       public List<Double> getLatLong(String address){
08          return strategy.getLatLong(address);
09       }
10   }

                                         Geocoder
                                                        strategies                 GeocodeService
          Client          + Geocoder(String)
                                                    1                       +getLatLong(String)
                          +getLatLong(String)                        *

                                                                 GoogleMapsImpl                           MapQuestImpl

                                                          +getLatLong(String)                     +getLatLong(String)


11   Geocoder geocoder = new Geocoder('googlemaps');
12   System.debug(geocoder.getLatLong('moscone center'));
13   //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0)
01   public class Geocoder {
02       public class NameException extends Exception{}
03       public static final Map<String,GeocodeService> strategies;
04       static{
05           GlobalVariable__c gv = GlobalVariable__c.getInstance('strategies');
06           List<String> strategyNames = new List<String>();
07           if(gv != null && gv.value__c != null) strategyNames = gv.value__c.split(',');
08           strategies = new Map<String,GeocodeService>();
09           for(String name : strategyNames){
10               try{strategies.put(name,(GeocodeService)Type.forName(name+'impl').newInstance());}
11               catch(Exception e){continue;} //skip bad name silently
12           }
13       }
14       private GeocodeService strategy;
15       public Geocoder(String name){
16           if(!strategies.containsKey(name)) throw new NameException(name);
17           strategy = strategies.get(name);
18       }
19       public List<Double> getLatLong(String address){
20           return strategy.getLatLong(address);
21       }
22   }
Patterns
1. Singleton
2. Strategy
3. ?
4. ?
5. ?
6. ?
Question?
 How do we extend the functionality of an sObject in Apex without adding new fields?




                                                          Transient selection
                                                             checkboxes




                                                                                Calculated Fields
                                                                                 with Updates
Solution – sObject Decorator
                                                              sObject


                                                   + Save()
                                                   ...




                                                      Concrete sObject
                          sObjectDecorator
                                                   + Field1
           VF        + sObj: sObject               + Field2
        Controller   + Property : type             ...
                                                   + Fieldn
                     + sObjectDecorator(sObject)
                     + Operation()                 + Save()
                                                   ...




                       (aka Wrapper Classes)
Example - Scenario
 Weather sObject
     City__c
     TempInFahrenheit__c (in Fahrenheit)

 VisualForce Requirements
     Stored temperature in Fahrenheit is displayed in Celcius
     User enters Temperature in Celcius and is stored to the record in Fahrenheit



                                                                              Bi-directional Display and
                                                                                      Calculation
The Code – Decorated sObject Class
   01   public class DecoratedWeather {
   02
   03        public Weather__c weather { get; private set; }
   04
   05        public DecoratedWeather (Weather__c weather) {
   06               this.weather = weather;
   07        }
   08
   09        public Decimal tempInCelcius {
   10             get {
   11                   if (weather != null && tempInCelcius == null )
   12                        tempInCelcius = new Temperature().FtoC(weather.TempInFahrenheit__c);
   13
   14                     return tempInCelcius;
   15             }
   16             set {
   17                     if (weather != null && value != null )
   18                          weather.TempInFahrenheit__c= new Temperature().CtoF(value);
   19
   20             tempInCelcius = value;
   21             }
   22        }
   23   }
The Code – Custom Controller
 01   public class Weather_Controller {
 02
 03       public List<DecoratedWeather> listOfWeather {
 04
 05             get {
 06                     if (listOfWeather == null) {
 07                          listOfWeather = new List<DecoratedWeather>();
 08
 09                     for (Weather__c weather : [select name, temperature__c from Weather__c]) {
 10                               listOfWeather.add(new DecoratedWeather(weather));
 11                          }
 12             }
 13                     return listOfWeather;
 14             }
 15
 16             private set;
 17       }
 18   }
The Code – VisualForce Page
 01   <apex:page controller="weather_controller">
 02
 03        <!-- VF page to render the weather records with Ajax that only rerenders
 04               the page on change of the temperature
 05        -->
 06       <apex:form id="theForm">
 07            <apex:pageBlock id="pageBlock">
 08                <apex:pageBlockTable value="{!listOfWeather}" var="weather">
 09                    <apex:column value="{!weather.weather.name}"/>
 10                    <apex:column headerValue="Temperature (C)">
 11                        <apex:actionRegion >
 12                            <apex:inputText value="{!weather.tempInCelcius}">
 13                                <apex:actionSupport event="onchange"
 14                                                reRender="pageBlock"/>
 15                            </apex:inputText>
 16                        </apex:actionRegion>
 17                    </apex:column>
 18                    <apex:column headerValue="Temperature (F)"
 19                                    value="{!weather.weather.Temperature__c}"
 20                                    id="tempInF"/>
 21                </apex:pageBlockTable>
 22              </apex:pageBlock>
 23       </apex:form>
 24   </apex:page>                                                        No client side
                                                                             logic!!!
Finally, on the VisualForce page
Patterns
1. Singleton
2. Strategy
3. sObject Decorater
4. ?
5. ?
6. ?
What’s wrong with this?

VisualForce Controller #1   VisualForce Controller #2




                            VisualForce Controller #3
Solution – Façade Pattern
          Client1                                               Foo1



                                     FooFacade           + Foo1() : String



                               + LotsOfFoo() : String
          Client2                                               Foo2


                                                         + Foo2() : String




                01   public String LotsOfFoo() {
                02       Foo1 f1 = new Foo1();
                03       Foo2 f2 = new Foo2();
                04
                05       return f1.Foo1() + f2.Foo2();
                06   }
Example - Scenario
 Composite Customer Create Transaction
      Create Account Web Service
      Create Contact Web Service
 Inputs
      UserId – current user
      Timestamp – current timestamp
      Account Name (Upper case transformation)
      Last Name and First Name
 Need to also set
      Timeout
      Hostname
 Returns Account and Contact Number from remote system
Code – Façade Class
  01   public class CreateCustomerFacade {
  02
  03      public class CreateCustomerResponse {
  04          public String accountNumber;
  05          public String contactNumber;
  06
  07             public CreateCustomerResponse(String accountNumber,
  08                                        String contactNumber) {
  09                 this.accountNumber = accountNumber;
  10                 this.contactNumber = contactNumber;
  11             }
  12       }
  13       ...
Code – Façade Class
  01   ...
  02   public String CreateCustomerExternal(String Name,
  03                    String LastName, String FirstName) {
  04       CreateAccount_Service.CreateAccount stubCA =
  05                           new CreateAccount_Service.CreateAccount();
  06       CreateAccount_Service.Inputs inputCA =
  07                           new CreateAccount_Service.Inputs();
  08
  09       stubCA.timeout_x = 60000;
  10       stubCA.endpoint_x = 'https://www.foo.com/ca';
  11
  12       inputCA.userid = Userinfo.getUserName();
  13       inputCA.timestamp = datetime.now();
  14       inputCA.Name = name.toUpperCase();
  15
  16       String accountNumber = inputCA.CreateAccount(input);
  17
  18       /* REPEAT FOR CONTACT */
  19
  20       return new CreateCustomerResponse (
  21                           accountNumber, contactNumber);
  22   }
Code – The Client

  01   public class FooController{
  02
  03       public Account account { get; set; }
  04       public Contact contact { get; set; }
  05       …
  06       public void CallCreateCustomerWS() {
  07           CreateCustomerFacade ca =
  08                 new CreateCustomerFacade();
  09
  10           CreateCustomerFacade.CreateCustomerResponse resp =
  11          ca.CreateCustomerExternal(account.name, contact.LastName,
  12   contact.FirstName);
  13
  14           account.accountNumber = resp.accountNumber;
  15           contact.contactNumber__c = resp.contactNumber;
           }
       }
Patterns
1. Singleton
2. Strategy
3. sObject Decorater
4. Façade
5. ?
6. ?
How do you represent
expressions?

1 AND 2
1 OR (2 AND 3)
(1 AND 2) OR ((3 OR 4) AND 5)
Solution: Composite                                                                        Component

                                                                                  +operation()                              children
                                                      Client                      +add(Component)
                                                                                  +remove(Component)
                                                                                  +get(Integer)
            1 AND 2
  Client                and : Composite

                                                                                  Leaf                          Composite
                    1 : Leaf       2 : Leaf
                                                                         +operation()               +operation()
                                                                                                    +add(Component)
                                                                                                    +remove(Component)
                                                                                                    +get(Integer)


              1 OR (2 AND 3)                                   (1 AND 2) OR ((3 OR 4) AND 5)
           Client                  or                           Client                         or


                               1            and                                      and                    and


                                        2         3                           1            2           or          5


                                                                                                3           4
Let’s Code It!
 01   public interface Expression {
 02       Expression add(Expression expr);
 03       Expression set(String name, Boolean value);
 04       Boolean evaluate();
 05   }

 06   public abstract class Composite implements Expression{
 07       public List<Expression> children {get; private set;}
 08       public Composite(){ this.children = new List<Expression>(); }
 09       public Expression add(Expression expr){
 10           children.add(expr); return this;
 11       }
 12       public Expression set(String name, Boolean value){
 13           for(Expression expr : children) expr.set(name,value);
 14           return this;
 15       }
 16       public abstract Boolean evaluate();
 17       public Boolean hasChildren{get{ return !children.isEmpty(); }}
 18   }
01   public class AndComposite extends Composite{
02       public override Boolean evaluate(){
03           for(Expression expr : children) if(!expr.evaluate()) return false;
04           return true;
05       }
06   }

07   public class OrComposite extends Composite{
08       public override Boolean evaluate(){
09           for(Expression expr : children) if(expr.evaluate()) return true;
10           return false;
11       }
12   }

13 public class Variable implements Expression{
14     public String name {get;private set;}
15     public Boolean value {get;private set;}
16     public Variable(String name){ this.name = name; }
17     public Expression add(Expression expr){ return this; }
18     public Expression set(String name, Boolean value){
19         if(this.name != null && this.name.equalsIgnoreCase(name))
20             this.value = value;
21         return this;
22     }
23     public Boolean evaluate(){ return value; }
24 }
Building Expressions
 01   //1 AND 2
 02   Expression expr = new AndComposite();
 03   expr.add(new Variable('1'));
 04   expr.add(new Variable('2'));

05    //1 OR (2 AND 3)
06    Expression expr = new OrComposite();
07    expr.add(new Variable('1'));
08    Expression expr2 = new AndComposite();
09    expr.add(expr2);
10    expr2.add(new Variable('2'));
11    expr2.add(new Variable('3'));

 12   //no need for expr2 var if using "method chaining"
 13   //last line of add method: return this;
 14   Expression expr = (new OrComposite())
 15       .add(new Variable('1'))
 16       .add((new AndComposite())
 17           .add(new Variable('2'))
 18           .add(new Variable('3'))
 19       );
Use Case
01   //1 OR (2 AND 3)
02   Expression expr = (new OrComposite())
03       .add(new Variable('1'))
04       .add((new AndComposite())
05           .add(new Variable('2'))
06           .add(new Variable('3'))
07       )
08       .set('1',false)
09       .set('2',true)
10       .set('3',false);
11
12   System.debug(expr.evaluate());
13   //FALSE OR (TRUE AND FALSE) => FALSE
14
15   expr.set('3',true);
16
17   System.debug(expr.evaluate());
18   //FALSE OR (TRUE AND TRUE) => TRUE
Patterns
1. Singleton
2. Strategy
3. sObject Decorater
4. Façade
5. Composite
6. ?
Billy Has a New Problem!

Billy wrote a trigger to create an order on close of an opportunity,
however:
  It always creates a new order every time the closed opportunity is updated
  When loading via Data Loader, not all closed opportunities result in an
   order
The Offending Code
01   trigger OpptyTrigger on Opportunity (after insert, after update) {
02
03       if (trigger.new[0].isClosed) {
04           Order__c order = new Order__c();
05           …                                                        Occurs regardless
06           insert order                                               of prior state
07       }                                      No Bulk
08   }                                          Handling



               Poor reusability
Any Better?
01   trigger OpptyTrigger on Opportunity (after insert, after update) {
02
03       new OrderClass().CreateOrder(trigger.new);
04
05   }

01   public class OrderClass {
02
03       public void CreateOrder(List<Opportunity> opptyList) {
04           for (Opportunity oppty : opptyList) {
05               if (oppty.isClosed) {
06                    Order__c order = new Order__c();
07                    ...                                    Occurs regardless
08                    insert order;                             of prior state
09               }
10           }
11
12       }
13   }                              Not bulkified
How’s this?
 01    trigger OpptyTrigger on Opportunity (before insert, before update) {
 02        if (trigger.isInsert) {
 03             new OrderClass().CreateOrder(trigger.newMap, null);
 04        else
0506            new OrderClass().CreateOrder(trigger.newMap, trigger.oldMap);
01    public class OrderClass {
02
03            public void CreateOrder(Map<Opportunity> opptyMapNew
04                                    Map<Opportunity> opptyMapOld) {
05                List<Order__c> orderList = new List<Order__c>();
06                for (Opportunity oppty : opptyMapNew.values()) {
07                    if (oppty.isClosed && (opptyMapOld == null ||
08                             !opptyMapOld.get(oppty.id).isClosed)) {
09 least it’s
At                         Order__c order = new Order__c();
10
 bulkified                 ...
11                         orderList.add(order);
12                    }                                                     This code is highly
13                }                                                      coupled and not reusable
14                insert orderList ;
15            }
Solution – Bulk Transition

                                                  Utility Class

              Trigger

                                           + Foo(sObject[])



       •   Checks for eligible records
           that have changed state and        •    Generic utility class method that can
           match criteria                          be called from any context
       •   Calls utility class method to
           perform the work
       •   Only eligible records are
           passed in
At Last!!!
 01   trigger OpptyTrigger on Opportunity (after insert, after update) {
 02       if (trigger.isAfter && (trigger.isInsert || trigger.isUpdate)) {
 03           List<Opportunity> closedOpptyList = new List<Opportunity>();
 04           for (Opportunity oppty : trigger.new) {
 05                if (oppty.isClosed && (trigger.isInsert ||
 06                         (trigger.isUpdate &&
 07                         !trigger.oldMap.get(oppty.id).isClosed)))
                                                                                  Trigger handles state
 08                    closedOpptyList.add(oppty);
                                                                                        transition
 09           }
 10           if (!closedOpptyList.isEmpty())
 11                new OrderClass().CreateOrderFromOpptys(closedOpptyList)

 01   public class OrderClass {
 02       public void CreateOrdersFromOpptys(List<Opportunity> opptyList) {
 03           List<Order__c> orderList = new List<Order__c>();
 04           for (Opportunity oppty : opptyList) {
 05                Order__c order = new Order__c();
 06                ...                                                       This method is now a lot
 07                orderList.add(order);                                    more reusable and is bulk-
 08           }                                                                       safe
 09           insert orderList ;
Patterns
1. Singleton
2. Strategy
3. sObject Decorater
4. Façade
5. Composite
6. Bulk State Transition
Resources
 Wrapper Classes - http://wiki.developerforce.com/page/Wrapper_Class
 Apex Code Best Practices -
 http://wiki.developerforce.com/page/Apex_Code_Best_Practices
 Apex Web Services and Callouts -
 http://wiki.developerforce.com/page/Apex_Web_Services_and_Callouts
 Sample Code - https://github.com/richardvanhook/Force.com-Patterns
More at #DF12

Hands-on Training: Introduction to Apex Patterns
Tuesday 3:30pm-6:00pm, Hilton Union Square, Continental Parlor 5
Thursday 12:00pm-2:30pm, Hilton Union Square, Continental Parlor 1/2/3
Dennis Thong                         Richard Vanhook
Senior Technical Solution Architect   Senior Technical Solution Architect
Here is how we can apply the Strategy pattern to meet Billy's requirements:1. Define a Strategy interface with an operation() method2. Create concrete Strategy classes for each provider (GoogleMaps, BingMaps, etc)   that implement operation() differently3. Create a Context class that holds a reference to a Strategy   and delegates operation() to the strategy4. Client code sets the strategy on Context and calls operation()   without knowing the concrete strategyThis allows switching providers easily and keeps client code decoupled.Let me know if any part needs more explanation

Weitere ähnliche Inhalte

Was ist angesagt?

Champion Productivity with Service Cloud
Champion Productivity with Service CloudChampion Productivity with Service Cloud
Champion Productivity with Service CloudSalesforce Admins
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceSalesforce Developers
 
Introduction to apex code
Introduction to apex codeIntroduction to apex code
Introduction to apex codeEdwinOstos
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce dataSalesforce Developers
 
Real Time Integration with Salesforce Platform Events
Real Time Integration with Salesforce Platform EventsReal Time Integration with Salesforce Platform Events
Real Time Integration with Salesforce Platform EventsSalesforce Developers
 
Salesforce Integration Patterns
Salesforce Integration PatternsSalesforce Integration Patterns
Salesforce Integration Patternsusolutions
 
Managing the Role Hierarchy at Enterprise Scale
Managing the Role Hierarchy at Enterprise ScaleManaging the Role Hierarchy at Enterprise Scale
Managing the Role Hierarchy at Enterprise ScaleSalesforce Developers
 
Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Salesforce Developers
 
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...Sam Garforth
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilitySalesforce Developers
 
Introduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelIntroduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelSalesforce Developers
 
Two-Way Integration with Writable External Objects
Two-Way Integration with Writable External ObjectsTwo-Way Integration with Writable External Objects
Two-Way Integration with Writable External ObjectsSalesforce Developers
 
oracle ebs free web service integration tools
oracle ebs free web service integration toolsoracle ebs free web service integration tools
oracle ebs free web service integration toolsSmartDog Services
 
Build Reliable Asynchronous Code with Queueable Apex
Build Reliable Asynchronous Code with Queueable ApexBuild Reliable Asynchronous Code with Queueable Apex
Build Reliable Asynchronous Code with Queueable ApexSalesforce Developers
 
OAuth with Salesforce - Demystified
OAuth with Salesforce - DemystifiedOAuth with Salesforce - Demystified
OAuth with Salesforce - DemystifiedCalvin Noronha
 
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSalesforce Developers
 
Making External Web Pages Interact With Visualforce
Making External Web Pages Interact With VisualforceMaking External Web Pages Interact With Visualforce
Making External Web Pages Interact With VisualforceSalesforce Developers
 
Salesforce Integration using REST SOAP and HTTP callouts
Salesforce Integration using REST SOAP and HTTP calloutsSalesforce Integration using REST SOAP and HTTP callouts
Salesforce Integration using REST SOAP and HTTP calloutsRAMNARAYAN R
 

Was ist angesagt? (20)

Champion Productivity with Service Cloud
Champion Productivity with Service CloudChampion Productivity with Service Cloud
Champion Productivity with Service Cloud
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component Performance
 
Introduction to apex code
Introduction to apex codeIntroduction to apex code
Introduction to apex code
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce data
 
Real Time Integration with Salesforce Platform Events
Real Time Integration with Salesforce Platform EventsReal Time Integration with Salesforce Platform Events
Real Time Integration with Salesforce Platform Events
 
Introduction to Apex Triggers
Introduction to Apex TriggersIntroduction to Apex Triggers
Introduction to Apex Triggers
 
Exploring the Salesforce REST API
Exploring the Salesforce REST APIExploring the Salesforce REST API
Exploring the Salesforce REST API
 
Salesforce Integration Patterns
Salesforce Integration PatternsSalesforce Integration Patterns
Salesforce Integration Patterns
 
Managing the Role Hierarchy at Enterprise Scale
Managing the Role Hierarchy at Enterprise ScaleManaging the Role Hierarchy at Enterprise Scale
Managing the Role Hierarchy at Enterprise Scale
 
Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex! Dive Deep into Apex: Advanced Apex!
Dive Deep into Apex: Advanced Apex!
 
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
Salesforce Application Lifecycle Management presented to EA Forum by Sam Garf...
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura Interoperability
 
Introduction to the Salesforce Security Model
Introduction to the Salesforce Security ModelIntroduction to the Salesforce Security Model
Introduction to the Salesforce Security Model
 
Two-Way Integration with Writable External Objects
Two-Way Integration with Writable External ObjectsTwo-Way Integration with Writable External Objects
Two-Way Integration with Writable External Objects
 
oracle ebs free web service integration tools
oracle ebs free web service integration toolsoracle ebs free web service integration tools
oracle ebs free web service integration tools
 
Build Reliable Asynchronous Code with Queueable Apex
Build Reliable Asynchronous Code with Queueable ApexBuild Reliable Asynchronous Code with Queueable Apex
Build Reliable Asynchronous Code with Queueable Apex
 
OAuth with Salesforce - Demystified
OAuth with Salesforce - DemystifiedOAuth with Salesforce - Demystified
OAuth with Salesforce - Demystified
 
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
 
Making External Web Pages Interact With Visualforce
Making External Web Pages Interact With VisualforceMaking External Web Pages Interact With Visualforce
Making External Web Pages Interact With Visualforce
 
Salesforce Integration using REST SOAP and HTTP callouts
Salesforce Integration using REST SOAP and HTTP calloutsSalesforce Integration using REST SOAP and HTTP callouts
Salesforce Integration using REST SOAP and HTTP callouts
 

Andere mochten auch

Salesforce Meetup 18 April 2015 - Apex Trigger & Scheduler Framworks
Salesforce Meetup 18 April 2015 - Apex Trigger & Scheduler FramworksSalesforce Meetup 18 April 2015 - Apex Trigger & Scheduler Framworks
Salesforce Meetup 18 April 2015 - Apex Trigger & Scheduler FramworksSumitkumar Shingavi
 
Salesforce Coding techniques that keep your admins happy (DF13)
Salesforce Coding techniques that keep your admins happy (DF13)Salesforce Coding techniques that keep your admins happy (DF13)
Salesforce Coding techniques that keep your admins happy (DF13)Roy Gilad
 
Batch Apex in Salesforce
Batch Apex in SalesforceBatch Apex in Salesforce
Batch Apex in SalesforceDavid Helgerson
 
Five Enterprise Best Practices That EVERY Salesforce Org Can Use (DF15 Session)
Five Enterprise Best Practices That EVERY Salesforce Org Can Use (DF15 Session)Five Enterprise Best Practices That EVERY Salesforce Org Can Use (DF15 Session)
Five Enterprise Best Practices That EVERY Salesforce Org Can Use (DF15 Session)Vivek Chawla
 
Salesforce World Tour 2016 : Lightning Out : Components on any Platform
Salesforce World Tour 2016 : Lightning Out : Components on any PlatformSalesforce World Tour 2016 : Lightning Out : Components on any Platform
Salesforce World Tour 2016 : Lightning Out : Components on any Platformandyinthecloud
 
Design Patterns for Asynchronous Apex
Design Patterns for Asynchronous ApexDesign Patterns for Asynchronous Apex
Design Patterns for Asynchronous ApexSalesforce Developers
 
Apex Trigger Debugging: Solving the Hard Problems
Apex Trigger Debugging: Solving the Hard ProblemsApex Trigger Debugging: Solving the Hard Problems
Apex Trigger Debugging: Solving the Hard ProblemsSalesforce Developers
 
From Sandbox To Production: An Introduction to Salesforce Release Management
From Sandbox To Production: An Introduction to Salesforce Release ManagementFrom Sandbox To Production: An Introduction to Salesforce Release Management
From Sandbox To Production: An Introduction to Salesforce Release ManagementSalesforce Developers
 
Secure Development on the Salesforce Platform - Part 3
Secure Development on the Salesforce Platform - Part 3Secure Development on the Salesforce Platform - Part 3
Secure Development on the Salesforce Platform - Part 3Mark Adcock
 
Advanced Apex Development - Asynchronous Processes
Advanced Apex Development - Asynchronous ProcessesAdvanced Apex Development - Asynchronous Processes
Advanced Apex Development - Asynchronous ProcessesSalesforce Developers
 
Salesforce Release Management - Best Practices and Tools for Deployment
Salesforce Release Management - Best Practices and Tools for DeploymentSalesforce Release Management - Best Practices and Tools for Deployment
Salesforce Release Management - Best Practices and Tools for DeploymentSalesforce Developers
 
Secure Development on the Salesforce Platform - Part I
Secure Development on the Salesforce Platform - Part ISecure Development on the Salesforce Platform - Part I
Secure Development on the Salesforce Platform - Part ISalesforce Developers
 
The Ideal Salesforce Development Lifecycle
The Ideal Salesforce Development LifecycleThe Ideal Salesforce Development Lifecycle
The Ideal Salesforce Development LifecycleJoshua Hoskins
 
Salesforce.com process map (from lead to opportunity)
Salesforce.com process map (from lead to opportunity)Salesforce.com process map (from lead to opportunity)
Salesforce.com process map (from lead to opportunity)Roger Borges Grilo
 

Andere mochten auch (20)

Apex collection patterns
Apex collection patternsApex collection patterns
Apex collection patterns
 
Salesforce Meetup 18 April 2015 - Apex Trigger & Scheduler Framworks
Salesforce Meetup 18 April 2015 - Apex Trigger & Scheduler FramworksSalesforce Meetup 18 April 2015 - Apex Trigger & Scheduler Framworks
Salesforce Meetup 18 April 2015 - Apex Trigger & Scheduler Framworks
 
Deep Dive into Apex Triggers
Deep Dive into Apex TriggersDeep Dive into Apex Triggers
Deep Dive into Apex Triggers
 
Salesforce Coding techniques that keep your admins happy (DF13)
Salesforce Coding techniques that keep your admins happy (DF13)Salesforce Coding techniques that keep your admins happy (DF13)
Salesforce Coding techniques that keep your admins happy (DF13)
 
Batch Apex in Salesforce
Batch Apex in SalesforceBatch Apex in Salesforce
Batch Apex in Salesforce
 
Five Enterprise Best Practices That EVERY Salesforce Org Can Use (DF15 Session)
Five Enterprise Best Practices That EVERY Salesforce Org Can Use (DF15 Session)Five Enterprise Best Practices That EVERY Salesforce Org Can Use (DF15 Session)
Five Enterprise Best Practices That EVERY Salesforce Org Can Use (DF15 Session)
 
Introduction to Apex Triggers
Introduction to Apex TriggersIntroduction to Apex Triggers
Introduction to Apex Triggers
 
Salesforce World Tour 2016 : Lightning Out : Components on any Platform
Salesforce World Tour 2016 : Lightning Out : Components on any PlatformSalesforce World Tour 2016 : Lightning Out : Components on any Platform
Salesforce World Tour 2016 : Lightning Out : Components on any Platform
 
Design Patterns for Asynchronous Apex
Design Patterns for Asynchronous ApexDesign Patterns for Asynchronous Apex
Design Patterns for Asynchronous Apex
 
Apex Trigger Debugging: Solving the Hard Problems
Apex Trigger Debugging: Solving the Hard ProblemsApex Trigger Debugging: Solving the Hard Problems
Apex Trigger Debugging: Solving the Hard Problems
 
Development lifecycle guide (part 1)
Development lifecycle guide (part 1)Development lifecycle guide (part 1)
Development lifecycle guide (part 1)
 
Governor limits
Governor limitsGovernor limits
Governor limits
 
From Sandbox To Production: An Introduction to Salesforce Release Management
From Sandbox To Production: An Introduction to Salesforce Release ManagementFrom Sandbox To Production: An Introduction to Salesforce Release Management
From Sandbox To Production: An Introduction to Salesforce Release Management
 
Secure Development on the Salesforce Platform - Part 3
Secure Development on the Salesforce Platform - Part 3Secure Development on the Salesforce Platform - Part 3
Secure Development on the Salesforce Platform - Part 3
 
Advanced Apex Development - Asynchronous Processes
Advanced Apex Development - Asynchronous ProcessesAdvanced Apex Development - Asynchronous Processes
Advanced Apex Development - Asynchronous Processes
 
Salesforce Release Management - Best Practices and Tools for Deployment
Salesforce Release Management - Best Practices and Tools for DeploymentSalesforce Release Management - Best Practices and Tools for Deployment
Salesforce Release Management - Best Practices and Tools for Deployment
 
Secure Development on the Salesforce Platform - Part I
Secure Development on the Salesforce Platform - Part ISecure Development on the Salesforce Platform - Part I
Secure Development on the Salesforce Platform - Part I
 
The Ideal Salesforce Development Lifecycle
The Ideal Salesforce Development LifecycleThe Ideal Salesforce Development Lifecycle
The Ideal Salesforce Development Lifecycle
 
Salesforce Data Structures
Salesforce Data StructuresSalesforce Data Structures
Salesforce Data Structures
 
Salesforce.com process map (from lead to opportunity)
Salesforce.com process map (from lead to opportunity)Salesforce.com process map (from lead to opportunity)
Salesforce.com process map (from lead to opportunity)
 

Ähnlich wie Here is how we can apply the Strategy pattern to meet Billy's requirements:1. Define a Strategy interface with an operation() method2. Create concrete Strategy classes for each provider (GoogleMaps, BingMaps, etc) that implement operation() differently3. Create a Context class that holds a reference to a Strategy and delegates operation() to the strategy4. Client code sets the strategy on Context and calls operation() without knowing the concrete strategyThis allows switching providers easily and keeps client code decoupled.Let me know if any part needs more explanation

Apex enterprise patterns
Apex enterprise patternsApex enterprise patterns
Apex enterprise patternsAmit Jain
 
Dependency injection - the right way
Dependency injection - the right wayDependency injection - the right way
Dependency injection - the right wayThibaud Desodt
 
Android DevConference - Android Clean Architecture
Android DevConference - Android Clean ArchitectureAndroid DevConference - Android Clean Architecture
Android DevConference - Android Clean ArchitectureiMasters
 
Introduction to Event Sourcing and CQRS (IASA-IL)
Introduction to Event Sourcing and CQRS (IASA-IL)Introduction to Event Sourcing and CQRS (IASA-IL)
Introduction to Event Sourcing and CQRS (IASA-IL)Vladik Khononov
 
Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Joshua Birk
 
Improving application design with a rich domain model (springone 2007)
Improving application design with a rich domain model (springone 2007)Improving application design with a rich domain model (springone 2007)
Improving application design with a rich domain model (springone 2007)Chris Richardson
 
MongoDB Stitch Tutorial
MongoDB Stitch TutorialMongoDB Stitch Tutorial
MongoDB Stitch TutorialMongoDB
 
From CRUD to messages: a true story
From CRUD to messages: a true storyFrom CRUD to messages: a true story
From CRUD to messages: a true storyAlessandro Melchiori
 
ELEVATE Advanced Workshop
ELEVATE Advanced WorkshopELEVATE Advanced Workshop
ELEVATE Advanced WorkshopJoshua Birk
 
Integrating Force.com with Heroku
Integrating Force.com with HerokuIntegrating Force.com with Heroku
Integrating Force.com with HerokuPat Patterson
 
Rajeev oops 2nd march
Rajeev oops 2nd marchRajeev oops 2nd march
Rajeev oops 2nd marchRajeev Sharan
 
Tech_Implementation of Complex ITIM Workflows
Tech_Implementation of Complex ITIM WorkflowsTech_Implementation of Complex ITIM Workflows
Tech_Implementation of Complex ITIM Workflows51 lecture
 
Aspect-Oriented Programming (AOP) in .NET
Aspect-Oriented Programming (AOP) in .NETAspect-Oriented Programming (AOP) in .NET
Aspect-Oriented Programming (AOP) in .NETYuriy Guts
 
Introduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKIntroduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKSalesforce Developers
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Juan Pablo
 
Refatorando com a API funcional do Java
Refatorando com a API funcional do JavaRefatorando com a API funcional do Java
Refatorando com a API funcional do JavaGiovane Liberato
 
Automatically Repairing Test Cases for Evolving Method Declarations
Automatically Repairing Test Cases for Evolving Method DeclarationsAutomatically Repairing Test Cases for Evolving Method Declarations
Automatically Repairing Test Cases for Evolving Method DeclarationsICSM 2010
 

Ähnlich wie Here is how we can apply the Strategy pattern to meet Billy's requirements:1. Define a Strategy interface with an operation() method2. Create concrete Strategy classes for each provider (GoogleMaps, BingMaps, etc) that implement operation() differently3. Create a Context class that holds a reference to a Strategy and delegates operation() to the strategy4. Client code sets the strategy on Context and calls operation() without knowing the concrete strategyThis allows switching providers easily and keeps client code decoupled.Let me know if any part needs more explanation (20)

Write bulletproof trigger code
Write bulletproof trigger codeWrite bulletproof trigger code
Write bulletproof trigger code
 
Apex enterprise patterns
Apex enterprise patternsApex enterprise patterns
Apex enterprise patterns
 
Dependency injection - the right way
Dependency injection - the right wayDependency injection - the right way
Dependency injection - the right way
 
Android DevConference - Android Clean Architecture
Android DevConference - Android Clean ArchitectureAndroid DevConference - Android Clean Architecture
Android DevConference - Android Clean Architecture
 
ELEVATE Paris
ELEVATE ParisELEVATE Paris
ELEVATE Paris
 
Introduction to Event Sourcing and CQRS (IASA-IL)
Introduction to Event Sourcing and CQRS (IASA-IL)Introduction to Event Sourcing and CQRS (IASA-IL)
Introduction to Event Sourcing and CQRS (IASA-IL)
 
Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Detroit ELEVATE Track 2
Detroit ELEVATE Track 2
 
Improving application design with a rich domain model (springone 2007)
Improving application design with a rich domain model (springone 2007)Improving application design with a rich domain model (springone 2007)
Improving application design with a rich domain model (springone 2007)
 
MongoDB Stitch Tutorial
MongoDB Stitch TutorialMongoDB Stitch Tutorial
MongoDB Stitch Tutorial
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
 
From CRUD to messages: a true story
From CRUD to messages: a true storyFrom CRUD to messages: a true story
From CRUD to messages: a true story
 
ELEVATE Advanced Workshop
ELEVATE Advanced WorkshopELEVATE Advanced Workshop
ELEVATE Advanced Workshop
 
Integrating Force.com with Heroku
Integrating Force.com with HerokuIntegrating Force.com with Heroku
Integrating Force.com with Heroku
 
Rajeev oops 2nd march
Rajeev oops 2nd marchRajeev oops 2nd march
Rajeev oops 2nd march
 
Tech_Implementation of Complex ITIM Workflows
Tech_Implementation of Complex ITIM WorkflowsTech_Implementation of Complex ITIM Workflows
Tech_Implementation of Complex ITIM Workflows
 
Aspect-Oriented Programming (AOP) in .NET
Aspect-Oriented Programming (AOP) in .NETAspect-Oriented Programming (AOP) in .NET
Aspect-Oriented Programming (AOP) in .NET
 
Introduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKIntroduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDK
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
Refatorando com a API funcional do Java
Refatorando com a API funcional do JavaRefatorando com a API funcional do Java
Refatorando com a API funcional do Java
 
Automatically Repairing Test Cases for Evolving Method Declarations
Automatically Repairing Test Cases for Evolving Method DeclarationsAutomatically Repairing Test Cases for Evolving Method Declarations
Automatically Repairing Test Cases for Evolving Method Declarations
 

Mehr von Salesforce Developers

Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base ComponentsSalesforce Developers
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsSalesforce Developers
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaSalesforce Developers
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentSalesforce Developers
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsSalesforce Developers
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsSalesforce Developers
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsSalesforce Developers
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and TestingSalesforce Developers
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionSalesforce Developers
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPSalesforce Developers
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceSalesforce Developers
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureSalesforce Developers
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DXSalesforce Developers
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectSalesforce Developers
 
Modern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesModern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesSalesforce Developers
 

Mehr von Salesforce Developers (20)

Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base Components
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer Highlights
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX India
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local Development
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web Components
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web Components
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer Highlights
 
Live coding with LWC
Live coding with LWCLive coding with LWC
Live coding with LWC
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and Testing
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An Introduction
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCP
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in Salesforce
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data Capture
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DX
 
Get Into Lightning Flow Development
Get Into Lightning Flow DevelopmentGet Into Lightning Flow Development
Get Into Lightning Flow Development
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS Connect
 
Introduction to MuleSoft
Introduction to MuleSoftIntroduction to MuleSoft
Introduction to MuleSoft
 
Modern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesModern App Dev: Modular Development Strategies
Modern App Dev: Modular Development Strategies
 
Dreamforce Developer Recap
Dreamforce Developer RecapDreamforce Developer Recap
Dreamforce Developer Recap
 
Vs Code for Salesforce Developers
Vs Code for Salesforce DevelopersVs Code for Salesforce Developers
Vs Code for Salesforce Developers
 

Here is how we can apply the Strategy pattern to meet Billy's requirements:1. Define a Strategy interface with an operation() method2. Create concrete Strategy classes for each provider (GoogleMaps, BingMaps, etc) that implement operation() differently3. Create a Context class that holds a reference to a Strategy and delegates operation() to the strategy4. Client code sets the strategy on Context and calls operation() without knowing the concrete strategyThis allows switching providers easily and keeps client code decoupled.Let me know if any part needs more explanation

  • 2. Dennis Thong Senior Technical Solution Architect Richard Vanhook Senior Technical Solution Architect
  • 3. Safe Harbor Safe harbor statement under the Private Securities Litigation Reform Act of 1995: This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward- looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or service availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services. The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and other litigation, risks associated with possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our annual report on Form 10-Q for the most recent fiscal quarter ended July 31, 2012. This documents and others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site. Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
  • 4. The Plan Cover six design patterns  Problem  Pattern Abstract  Code Your participation is encouraged!
  • 5. Patterns 1. ? 2. ? 3. ? 4. ? 5. ? 6. ?
  • 6. Meet Billy, Your Admin • 3+ yrs as Salesforce Admin • Just recently started coding • Sad because of this: Trigger.AccountTrigger: line 3, column 1 System.LimitException: Too many record type describes: 101 • Needs your help!
  • 7. The Offending Code 01 trigger AccountTrigger on Account (before insert, before update) { 02 for(Account record : Trigger.new){ 03 AccountFooRecordType rt = new AccountFooRecordType(); 04 .... 05 } 06 } 07 public class AccountFooRecordType { 08 public String id {get;private set;} 09 public AccountFooRecordType(){ 10 id = Account.sObjectType.getDescribe() 11 .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); 12 } 13 } • When a single Account is inserted, what happens? • When 200+ Accounts are inserted…?
  • 8. Solution: Singleton Singleton - instance : Singleton - Singleton() + getInstance() : Singleton
  • 9. Let’s Code It! 01 trigger AccountTrigger on Account (before insert, before update) { 02 for(Account record : Trigger.new){ 03 AccountFooRecordType rt = new AccountFooRecordType(); 04 .... 05 } 06 } 07 public class AccountFooRecordType { 08 public String id {get;private set;} 09 public AccountFooRecordType(){ 10 id = Account.sObjectType.getDescribe() 11 .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); 12 } 13 } • Above is the offending code again • Changes are highlighted in next slides
  • 10. Let’s Code It! 01 trigger AccountTrigger on Account (before insert, before update) { 02 for(Account record : Trigger.new){ 03 AccountFooRecordType rt = (new AccountFooRecordType()).getInstance(); 04 .... 05 } 06 } 07 public class AccountFooRecordType { 08 public String id {get;private set;} 09 public AccountFooRecordType(){ 10 id = Account.sObjectType.getDescribe() 11 .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); 12 } 13 public AccountFooRecordType getInstance(){ 14 return new AccountFooRecordType(); 15 } 16 }
  • 11. Let’s Code It! 01 trigger AccountTrigger on Account (before insert, before update) { 02 for(Account record : Trigger.new){ 03 AccountFooRecordType rt = AccountFooRecordType.getInstance(); 04 .... 05 } 06 } 07 public class AccountFooRecordType { 08 public String id {get;private set;} 09 public AccountFooRecordType(){ 10 id = Account.sObjectType.getDescribe() 11 .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); 12 } 13 public static AccountFooRecordType getInstance(){ 14 return new AccountFooRecordType(); 15 } 16 }
  • 12. Static • Can modify member variables, methods, and blocks • Executed when? • When class is introduced (loaded) to runtime environment • How long does that last in Java? • Life of the JVM • In Apex? • Life of the transaction
  • 13. Let’s Code It! 01 trigger AccountTrigger on Account (before insert, before update) { 02 for(Account record : Trigger.new){ 03 AccountFooRecordType rt = AccountFooRecordType.getInstance(); 04 .... 05 } 06 } 07 public class AccountFooRecordType { 08 public String id {get;private set;} 09 public AccountFooRecordType(){ 10 id = Account.sObjectType.getDescribe() 11 .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); 12 } 13 public static AccountFooRecordType getInstance(){ 14 return new AccountFooRecordType(); 15 } 16 }
  • 14. Let’s Code It! 01 trigger AccountTrigger on Account (before insert, before update) { 02 for(Account record : Trigger.new){ 03 AccountFooRecordType rt = AccountFooRecordType.getInstance(); 04 .... 05 } 06 } 07 public class AccountFooRecordType { 08 public static AccountFooRecordType instance = null; 09 public String id {get;private set;} 10 public AccountFooRecordType(){ 11 id = Account.sObjectType.getDescribe() 12 .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); 13 } 14 public static AccountFooRecordType getInstance(){ 15 if(instance == null) instance = new AccountFooRecordType(); 16 return instance; 17 } 18 }
  • 15. Let’s Code It! 01 trigger AccountTrigger on Account (before insert, before update) { 02 for(Account record : Trigger.new){ 03 AccountFooRecordType rt = AccountFooRecordType.getInstance(); 04 .... 05 } 06 } 07 public class AccountFooRecordType { 08 private static AccountFooRecordType instance = null; 09 public String id {get;private set;} 10 public AccountFooRecordType(){ 11 id = Account.sObjectType.getDescribe() 12 .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); 13 } 14 public static AccountFooRecordType getInstance(){ 15 if(instance == null) instance = new AccountFooRecordType(); 16 return instance; 17 } 18 }
  • 16. Let’s Code It! 01 trigger AccountTrigger on Account (before insert, before update) { 02 for(Account record : Trigger.new){ 03 AccountFooRecordType rt = AccountFooRecordType.getInstance(); 04 .... 05 } 06 } 07 public class AccountFooRecordType { 08 private static AccountFooRecordType instance = null; 09 public String id {get;private set;} 10 private AccountFooRecordType(){ 11 id = Account.sObjectType.getDescribe() 12 .getRecordTypeInfosByName().get('Foo').getRecordTypeId(); 13 } 14 public static AccountFooRecordType getInstance(){ 15 if(instance == null) instance = new AccountFooRecordType(); 16 return instance; 17 } 18 }
  • 17. Patterns 1. Singleton 2. ? 3. ? 4. ? 5. ? 6. ?
  • 19. Your Suggestion to Billy 01 public class GoogleMapsGeocoder{ 02 public static List<Double> getLatLong(String address){ 03 //web service callout of some sort 04 return new List<Double>{0,0}; 05 } 06 } 07 System.debug(GoogleMapsGeocoder.getLatLong('moscone center')); 08 //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0) But then Billy mentions these requirements  Need other options besides Google Maps  Allow client code to choose provider
  • 20. Solution: Strategy Context strategies Strategy Client +operation() 1 +operation() * defines a family of algorithms, ConcreteStrategyA ConcreteStrategyB encapsulates each one, and makes +operation() +operation() them interchangeable  Context => Geocoder  operation() => getLatLong()  Strategy => GeocodeService  ConcreteStrategyA => GoogleMapsImpl  ConcreteStrategyB => MapQuestImpl
  • 21. Let’s Code It! 01 public interface GeocodeService{ 02 List<Double> getLatLong(String address); 03 } 04 public class GoogleMapsImpl implements GeocodeService{ 05 public List<Double> getLatLong(String address){ 06 return new List<Double>{0,0}; 07 } 08 } 09 public class MapQuestImpl implements GeocodeService{ 10 public List<Double> getLatLong(String address){ 11 return new List<Double>{1,1}; 12 } 13 }
  • 22. 01 public class Geocoder { 02 private GeocodeService strategy; 03 public Geocoder(GeocodeService s){ 04 strategy = s; 05 } 06 public List<Double> getLatLong(String address){ 07 return strategy.getLatLong(address); 08 } 09 } Geocoder strategies GeocodeService Client + Geocoder(GeocodeService) 1 +getLatLong(String) +getLatLong(String) * GoogleMapsImpl MapQuestImpl +getLatLong(String) +getLatLong(String) 10 Geocoder geocoder = new Geocoder(new GoogleMapsImpl()); 11 System.debug(geocoder.getLatLong('moscone center')); 12 //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0)
  • 23. 01 public class Geocoder { 02 public static final Map<String,Strategy> strategies = new 03 Map<String,Strategy>{'googlemaps' => new GoogleMapsImpl() 04 ,'mapquest' => new MapQuestImpl()}; 05 private GeocodeService strategy; 06 public Geocoder(String name){ strategy = strategies.get(name);} 07 public List<Double> getLatLong(String address){ 08 return strategy.getLatLong(address); 09 } 10 } Geocoder strategies GeocodeService Client + Geocoder(String) 1 +getLatLong(String) +getLatLong(String) * GoogleMapsImpl MapQuestImpl +getLatLong(String) +getLatLong(String) 11 Geocoder geocoder = new Geocoder('googlemaps'); 12 System.debug(geocoder.getLatLong('moscone center')); 13 //=> 13:56:36.029 (29225000)|USER_DEBUG|[29]|DEBUG|(0.0, 0.0)
  • 24. 01 public class Geocoder { 02 public class NameException extends Exception{} 03 public static final Map<String,GeocodeService> strategies; 04 static{ 05 GlobalVariable__c gv = GlobalVariable__c.getInstance('strategies'); 06 List<String> strategyNames = new List<String>(); 07 if(gv != null && gv.value__c != null) strategyNames = gv.value__c.split(','); 08 strategies = new Map<String,GeocodeService>(); 09 for(String name : strategyNames){ 10 try{strategies.put(name,(GeocodeService)Type.forName(name+'impl').newInstance());} 11 catch(Exception e){continue;} //skip bad name silently 12 } 13 } 14 private GeocodeService strategy; 15 public Geocoder(String name){ 16 if(!strategies.containsKey(name)) throw new NameException(name); 17 strategy = strategies.get(name); 18 } 19 public List<Double> getLatLong(String address){ 20 return strategy.getLatLong(address); 21 } 22 }
  • 26. Question? How do we extend the functionality of an sObject in Apex without adding new fields? Transient selection checkboxes Calculated Fields with Updates
  • 27. Solution – sObject Decorator sObject + Save() ... Concrete sObject sObjectDecorator + Field1 VF + sObj: sObject + Field2 Controller + Property : type ... + Fieldn + sObjectDecorator(sObject) + Operation() + Save() ... (aka Wrapper Classes)
  • 28. Example - Scenario Weather sObject  City__c  TempInFahrenheit__c (in Fahrenheit) VisualForce Requirements  Stored temperature in Fahrenheit is displayed in Celcius  User enters Temperature in Celcius and is stored to the record in Fahrenheit Bi-directional Display and Calculation
  • 29. The Code – Decorated sObject Class 01 public class DecoratedWeather { 02 03 public Weather__c weather { get; private set; } 04 05 public DecoratedWeather (Weather__c weather) { 06 this.weather = weather; 07 } 08 09 public Decimal tempInCelcius { 10 get { 11 if (weather != null && tempInCelcius == null ) 12 tempInCelcius = new Temperature().FtoC(weather.TempInFahrenheit__c); 13 14 return tempInCelcius; 15 } 16 set { 17 if (weather != null && value != null ) 18 weather.TempInFahrenheit__c= new Temperature().CtoF(value); 19 20 tempInCelcius = value; 21 } 22 } 23 }
  • 30. The Code – Custom Controller 01 public class Weather_Controller { 02 03 public List<DecoratedWeather> listOfWeather { 04 05 get { 06 if (listOfWeather == null) { 07 listOfWeather = new List<DecoratedWeather>(); 08 09 for (Weather__c weather : [select name, temperature__c from Weather__c]) { 10 listOfWeather.add(new DecoratedWeather(weather)); 11 } 12 } 13 return listOfWeather; 14 } 15 16 private set; 17 } 18 }
  • 31. The Code – VisualForce Page 01 <apex:page controller="weather_controller"> 02 03 <!-- VF page to render the weather records with Ajax that only rerenders 04 the page on change of the temperature 05 --> 06 <apex:form id="theForm"> 07 <apex:pageBlock id="pageBlock"> 08 <apex:pageBlockTable value="{!listOfWeather}" var="weather"> 09 <apex:column value="{!weather.weather.name}"/> 10 <apex:column headerValue="Temperature (C)"> 11 <apex:actionRegion > 12 <apex:inputText value="{!weather.tempInCelcius}"> 13 <apex:actionSupport event="onchange" 14 reRender="pageBlock"/> 15 </apex:inputText> 16 </apex:actionRegion> 17 </apex:column> 18 <apex:column headerValue="Temperature (F)" 19 value="{!weather.weather.Temperature__c}" 20 id="tempInF"/> 21 </apex:pageBlockTable> 22 </apex:pageBlock> 23 </apex:form> 24 </apex:page> No client side logic!!!
  • 32. Finally, on the VisualForce page
  • 33. Patterns 1. Singleton 2. Strategy 3. sObject Decorater 4. ? 5. ? 6. ?
  • 34. What’s wrong with this? VisualForce Controller #1 VisualForce Controller #2 VisualForce Controller #3
  • 35. Solution – Façade Pattern Client1 Foo1 FooFacade + Foo1() : String + LotsOfFoo() : String Client2 Foo2 + Foo2() : String 01 public String LotsOfFoo() { 02 Foo1 f1 = new Foo1(); 03 Foo2 f2 = new Foo2(); 04 05 return f1.Foo1() + f2.Foo2(); 06 }
  • 36. Example - Scenario Composite Customer Create Transaction  Create Account Web Service  Create Contact Web Service Inputs  UserId – current user  Timestamp – current timestamp  Account Name (Upper case transformation)  Last Name and First Name Need to also set  Timeout  Hostname Returns Account and Contact Number from remote system
  • 37. Code – Façade Class 01 public class CreateCustomerFacade { 02 03 public class CreateCustomerResponse { 04 public String accountNumber; 05 public String contactNumber; 06 07 public CreateCustomerResponse(String accountNumber, 08 String contactNumber) { 09 this.accountNumber = accountNumber; 10 this.contactNumber = contactNumber; 11 } 12 } 13 ...
  • 38. Code – Façade Class 01 ... 02 public String CreateCustomerExternal(String Name, 03 String LastName, String FirstName) { 04 CreateAccount_Service.CreateAccount stubCA = 05 new CreateAccount_Service.CreateAccount(); 06 CreateAccount_Service.Inputs inputCA = 07 new CreateAccount_Service.Inputs(); 08 09 stubCA.timeout_x = 60000; 10 stubCA.endpoint_x = 'https://www.foo.com/ca'; 11 12 inputCA.userid = Userinfo.getUserName(); 13 inputCA.timestamp = datetime.now(); 14 inputCA.Name = name.toUpperCase(); 15 16 String accountNumber = inputCA.CreateAccount(input); 17 18 /* REPEAT FOR CONTACT */ 19 20 return new CreateCustomerResponse ( 21 accountNumber, contactNumber); 22 }
  • 39. Code – The Client 01 public class FooController{ 02 03 public Account account { get; set; } 04 public Contact contact { get; set; } 05 … 06 public void CallCreateCustomerWS() { 07 CreateCustomerFacade ca = 08 new CreateCustomerFacade(); 09 10 CreateCustomerFacade.CreateCustomerResponse resp = 11 ca.CreateCustomerExternal(account.name, contact.LastName, 12 contact.FirstName); 13 14 account.accountNumber = resp.accountNumber; 15 contact.contactNumber__c = resp.contactNumber; } }
  • 40. Patterns 1. Singleton 2. Strategy 3. sObject Decorater 4. Façade 5. ? 6. ?
  • 41. How do you represent expressions? 1 AND 2 1 OR (2 AND 3) (1 AND 2) OR ((3 OR 4) AND 5)
  • 42. Solution: Composite Component +operation() children Client +add(Component) +remove(Component) +get(Integer) 1 AND 2 Client and : Composite Leaf Composite 1 : Leaf 2 : Leaf +operation() +operation() +add(Component) +remove(Component) +get(Integer) 1 OR (2 AND 3) (1 AND 2) OR ((3 OR 4) AND 5) Client or Client or 1 and and and 2 3 1 2 or 5 3 4
  • 43. Let’s Code It! 01 public interface Expression { 02 Expression add(Expression expr); 03 Expression set(String name, Boolean value); 04 Boolean evaluate(); 05 } 06 public abstract class Composite implements Expression{ 07 public List<Expression> children {get; private set;} 08 public Composite(){ this.children = new List<Expression>(); } 09 public Expression add(Expression expr){ 10 children.add(expr); return this; 11 } 12 public Expression set(String name, Boolean value){ 13 for(Expression expr : children) expr.set(name,value); 14 return this; 15 } 16 public abstract Boolean evaluate(); 17 public Boolean hasChildren{get{ return !children.isEmpty(); }} 18 }
  • 44. 01 public class AndComposite extends Composite{ 02 public override Boolean evaluate(){ 03 for(Expression expr : children) if(!expr.evaluate()) return false; 04 return true; 05 } 06 } 07 public class OrComposite extends Composite{ 08 public override Boolean evaluate(){ 09 for(Expression expr : children) if(expr.evaluate()) return true; 10 return false; 11 } 12 } 13 public class Variable implements Expression{ 14 public String name {get;private set;} 15 public Boolean value {get;private set;} 16 public Variable(String name){ this.name = name; } 17 public Expression add(Expression expr){ return this; } 18 public Expression set(String name, Boolean value){ 19 if(this.name != null && this.name.equalsIgnoreCase(name)) 20 this.value = value; 21 return this; 22 } 23 public Boolean evaluate(){ return value; } 24 }
  • 45. Building Expressions 01 //1 AND 2 02 Expression expr = new AndComposite(); 03 expr.add(new Variable('1')); 04 expr.add(new Variable('2')); 05 //1 OR (2 AND 3) 06 Expression expr = new OrComposite(); 07 expr.add(new Variable('1')); 08 Expression expr2 = new AndComposite(); 09 expr.add(expr2); 10 expr2.add(new Variable('2')); 11 expr2.add(new Variable('3')); 12 //no need for expr2 var if using "method chaining" 13 //last line of add method: return this; 14 Expression expr = (new OrComposite()) 15 .add(new Variable('1')) 16 .add((new AndComposite()) 17 .add(new Variable('2')) 18 .add(new Variable('3')) 19 );
  • 46. Use Case 01 //1 OR (2 AND 3) 02 Expression expr = (new OrComposite()) 03 .add(new Variable('1')) 04 .add((new AndComposite()) 05 .add(new Variable('2')) 06 .add(new Variable('3')) 07 ) 08 .set('1',false) 09 .set('2',true) 10 .set('3',false); 11 12 System.debug(expr.evaluate()); 13 //FALSE OR (TRUE AND FALSE) => FALSE 14 15 expr.set('3',true); 16 17 System.debug(expr.evaluate()); 18 //FALSE OR (TRUE AND TRUE) => TRUE
  • 47. Patterns 1. Singleton 2. Strategy 3. sObject Decorater 4. Façade 5. Composite 6. ?
  • 48. Billy Has a New Problem! Billy wrote a trigger to create an order on close of an opportunity, however:  It always creates a new order every time the closed opportunity is updated  When loading via Data Loader, not all closed opportunities result in an order
  • 49. The Offending Code 01 trigger OpptyTrigger on Opportunity (after insert, after update) { 02 03 if (trigger.new[0].isClosed) { 04 Order__c order = new Order__c(); 05 … Occurs regardless 06 insert order of prior state 07 } No Bulk 08 } Handling Poor reusability
  • 50. Any Better? 01 trigger OpptyTrigger on Opportunity (after insert, after update) { 02 03 new OrderClass().CreateOrder(trigger.new); 04 05 } 01 public class OrderClass { 02 03 public void CreateOrder(List<Opportunity> opptyList) { 04 for (Opportunity oppty : opptyList) { 05 if (oppty.isClosed) { 06 Order__c order = new Order__c(); 07 ... Occurs regardless 08 insert order; of prior state 09 } 10 } 11 12 } 13 } Not bulkified
  • 51. How’s this? 01 trigger OpptyTrigger on Opportunity (before insert, before update) { 02 if (trigger.isInsert) { 03 new OrderClass().CreateOrder(trigger.newMap, null); 04 else 0506 new OrderClass().CreateOrder(trigger.newMap, trigger.oldMap); 01 public class OrderClass { 02 03 public void CreateOrder(Map<Opportunity> opptyMapNew 04 Map<Opportunity> opptyMapOld) { 05 List<Order__c> orderList = new List<Order__c>(); 06 for (Opportunity oppty : opptyMapNew.values()) { 07 if (oppty.isClosed && (opptyMapOld == null || 08 !opptyMapOld.get(oppty.id).isClosed)) { 09 least it’s At Order__c order = new Order__c(); 10 bulkified ... 11 orderList.add(order); 12 } This code is highly 13 } coupled and not reusable 14 insert orderList ; 15 }
  • 52. Solution – Bulk Transition Utility Class Trigger + Foo(sObject[]) • Checks for eligible records that have changed state and • Generic utility class method that can match criteria be called from any context • Calls utility class method to perform the work • Only eligible records are passed in
  • 53. At Last!!! 01 trigger OpptyTrigger on Opportunity (after insert, after update) { 02 if (trigger.isAfter && (trigger.isInsert || trigger.isUpdate)) { 03 List<Opportunity> closedOpptyList = new List<Opportunity>(); 04 for (Opportunity oppty : trigger.new) { 05 if (oppty.isClosed && (trigger.isInsert || 06 (trigger.isUpdate && 07 !trigger.oldMap.get(oppty.id).isClosed))) Trigger handles state 08 closedOpptyList.add(oppty); transition 09 } 10 if (!closedOpptyList.isEmpty()) 11 new OrderClass().CreateOrderFromOpptys(closedOpptyList) 01 public class OrderClass { 02 public void CreateOrdersFromOpptys(List<Opportunity> opptyList) { 03 List<Order__c> orderList = new List<Order__c>(); 04 for (Opportunity oppty : opptyList) { 05 Order__c order = new Order__c(); 06 ... This method is now a lot 07 orderList.add(order); more reusable and is bulk- 08 } safe 09 insert orderList ;
  • 54. Patterns 1. Singleton 2. Strategy 3. sObject Decorater 4. Façade 5. Composite 6. Bulk State Transition
  • 55. Resources Wrapper Classes - http://wiki.developerforce.com/page/Wrapper_Class Apex Code Best Practices - http://wiki.developerforce.com/page/Apex_Code_Best_Practices Apex Web Services and Callouts - http://wiki.developerforce.com/page/Apex_Web_Services_and_Callouts Sample Code - https://github.com/richardvanhook/Force.com-Patterns
  • 56. More at #DF12 Hands-on Training: Introduction to Apex Patterns Tuesday 3:30pm-6:00pm, Hilton Union Square, Continental Parlor 5 Thursday 12:00pm-2:30pm, Hilton Union Square, Continental Parlor 1/2/3
  • 57. Dennis Thong Richard Vanhook Senior Technical Solution Architect Senior Technical Solution Architect