SlideShare a Scribd company logo
Apex のデザインパターン
開発者向けセッション
河村  嘉之
テクニカルソリューションアーキテクト
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.
セッションの進め⽅方
6 つのデザインパターンを扱う
 §  問題
 §  パターンの概要
 §  コード
積極的な発⾔言を歓迎します!
6 つのパターン
1.  ?
2.  ?
3.  ?
4.  ?
5.  ?
6.  ?
システム管理理者のビリーの場合

      •  Salesforce の管理理を担当して 3 年年
      •  コーディングはつい最近始めたばかり
      •  エラーのせいで落落ち込んでいます

        Trigger.AccountTrigger: line 3, column 1
        System.LimitException: Too many record
        type describes: 101


      •  助けが必要!
問題のコード
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   }



     •  1 件の Account (取引先) レコードが挿⼊入されたらどうなるか?
     •  200 件以上の Account が挿⼊入されたら…?
ソリューション – Singleton




                         Singleton

              - instance : Singleton

              - Singleton()
              + getInstance() : Singleton
コードを書いてみる
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   }



     •  これは先ほどと同じコード
     •  変更更点は次のスライドでハイライト表⽰示します
コードを書いてみる
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   }
コードを書いてみる
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

 •  メンバー変数、メソッド、ブロックを修飾可能
 •  実⾏行行のタイミングは?
     •    クラスがランタイム環境にロードされるとき

 •  Java で保持される期間は?
     •    JVM が実⾏行行されている間

 •  Apex では?
     •    トランザクションが実⾏行行されている間
コードを書いてみる
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   }
コードを書いてみる
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   }
コードを書いてみる
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   }
コードを書いてみる
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   }
6 つのパターン
1.  Singleton
2.  ?
3.  ?
4.  ?
5.  ?
6.  ?
geocode('moscone center')
//=> 37.7845935,-122.3994262
ビリーに提案したコードはこちら
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)




      すると、ビリーはこんな要件を挙げてきました
      §  Google マップのほかにも選択肢が必要
      §  クライアントコードでプロバイダを選べるようにしたい
ソリューション – Strategy
                                        Context            strategies           Strategy
               Client
                                   +operation()                             +operation()
                                                       1
                                                                        *
 構造的なアルゴリズムを定義し、
                                                       ConcreteStrategyA                        ConcreteStrategyB
 各アルゴリズムをカプセル化して、
                                                  +operation()                             +operation()
 相互に切切り替え可能にする
 §  Context => Geocoder
 §  operation() => getLatLong()
 §  Strategy => GeocodeService
 §  ConcreteStrategyA => GoogleMapsImpl
 §  ConcreteStrategyB => MapQuestImpl
コードを書いてみる
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   }
6 つのパターン
1.  Singleton
2.  Strategy
3.  ?
4.  ?
5.  ?
6.  ?
次の問題は?
Apex で項⽬目を追加せずに、sObject の機能を拡張するにはどうすればよいか?




                                 処理理の途中で選択の
                                チェックボックスを表⽰示




                                               更更新にもとづいて
                                                項⽬目の値を計算
ソリューション – sObject Decorator
                                                            sObject


                                                 + Save()
                                                 ...




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




                   (「ラッパークラス」と呼ばれる)
サンプルのシナリオ
天気の情報を格納する sObject 「Weather」
 §  「City__c」(市)
 §  「TempInFahrenheit__c」(華⽒氏換算の気温)

Visualforce ページ作成にあたっての要件
 §  Temperature レコードに格納されている華⽒氏の気温データを、摂⽒氏で表⽰示する
 §  Temperature レコードに摂⽒氏で⼊入⼒力力される気温データを、華⽒氏のデータとして保存する




                                                   双⽅方向で
                                                データを換算して表⽰示
コード – Decorator による sObject クラスの拡張
    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   }
コード – カスタムコントローラ
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   }
コード – Visualforce ページ
 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>
完成した  Visualforce ページ
6 つのパターン
1.  Singleton
2.  Strategy
3.  sObject Decorater
4.  ?
5.  ?
6.  ?
このコードの問題は?

Visualforce コントローラ 1   Visualforce コントローラ 2




                       Visualforce コントローラ 3
ソリューション – Façade
       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   }
サンプルのシナリオ
Customer (顧客) レコードを作成する、複数の処理理から成るトランザクション
  §  CreateAccount Web サービス – 取引先レコードを作成
  §  CreateContact Web サービス – 取引先責任者レコードを作成
⼊入⼒力力
  §  UserId – 現在のユーザ
  §  Timestamp – 現在のタイムスタンプ
  §  Name – 取引先名 (⼤大⽂文字に変換)
  §  LastName、FirstName – 取引先責任者の姓、名
その他に設定すべき項⽬目
  §  Timeout – タイムアウト値
  §  Hostname – ホスト名
リモートシステムから取引先と取引先責任者の追跡番号が返される
コード – Façade クラス
  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       ...
コード – Façade クラス
  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   }
コード – クライアント

01   public class FooController{
02
03       public Account account { get; set; }
04       public Contact contact { get; set; }
05       …
         public void CallCreateCustomerWS() {
06
             CreateCustomerFacade ca =
07
                   new CreateCustomerFacade();
08
09           CreateCustomerFacade.CreateCustomerResponse resp =
10                                                    ca.CreateCustomerExternal(account.name,
11   contact.LastName, contact.FirstName);
12
13           account.accountNumber = resp.accountNumber;
14           contact.contactNumber__c = resp.contactNumber;
15       }
     }
6 つのパターン
1.  Singleton
2.  Strategy
3.  sObject Decorater
4.  Façade
5.  ?
6.  ?
式をどうやって表現するか?

1 AND 2
1 OR (2 AND 3)
(1 AND 2) OR ((3 OR 4) AND 5)
ソリューション – 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
コードを書いてみる
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 }
式を作成する
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       );
式の使⽤用例例
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
6 つのパターン
1.  Singleton
2.  Strategy
3.  sObject Decorater
4.  Façade
5.  Composite
6.  ?
ビリーが新たな問題に直⾯面しています
Opportunity (商談) レコードがクローズされたタイミングで
Order (注⽂文) レコードを作成するトリガを記述したつもりだったが…
 §  クローズ済みの商談レコードが更更新されるたびに注⽂文レコードが作成されてしまう
 §  Apex データローダを使ってインポートを実⾏行行した場合に、
     クローズ済みの商談レコードの⼀一部で注⽂文レコードが作成されないことがある
問題のコード
01   trigger OpptyTrigger on Opportunity (after insert, after update) {
02
03          if (trigger.new[0].isClosed) {
04                 Order__c order = new Order__c();
05                 …                                                  前の状態がどうであるかに
                                                                       関係なく実⾏行行される
06                 insert order
07          }                                  バルク処理理に
08   }                                        対応していない



                  再利利⽤用性が低い
こうしたらどうか?
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                               ...
08                               insert order;                       前の状態がどうであるかに
                                                                      関係なく実⾏行行される
09                        }
10                 }
11
12          }                     バルク処理理に
13   }                           対応していない
ではこうしたら?
 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                              Order__c order = new Order__c();
OK  になった
 10                              ...
 11                              orderList.add(order);
 12                       }                                          コードのコンテキスト依存度度が
 13                }                                                    ⾼高く、再利利⽤用が難しい
 14                insert orderList ;
 15         }
ソリューション – "Bulk State Transition" (バルク状態遷移)

                                      Utility Class

             Trigger

                                  + Foo(sObject[])




      •    状態が変更更されたレコードの中で、         •    あらゆるコンテキストから
           条件に⼀一致するものを検出                  呼び出せるユーティリティクラスの
      •    所定の処理理を実⾏行行するユーティリティ           汎⽤用的なメソッド
           クラスのメソッドを呼び出す
      •    条件を満たすレコードのみを
           ユーティリティクラスに渡す
これで問題解決!!!
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)))   トリガが状態遷移を
08                               closedOpptyList.add(oppty);                          適切切に処理理
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                        ...                                                 再利利⽤用性が⾼高まり、
07                        orderList.add(order);                               バルク処理理にも対応
08                 }
09                 insert orderList ;
6 つのパターン
1.  Singleton
2.  Strategy
3.  sObject Decorater
4.  Façade
5.  Composite
6.  Bulk State Transition
関連リソース
ラッパークラス
http://wiki.developerforce.com/page/Wrapper_Class (英語)

Apex コードに関するベストプラクティス
http://wiki.developerforce.com/page/Apex_Code_Best_Practices (英語)

Apex の Web サービスとコールアウト
http://wiki.developerforce.com/page/JP:Apex_Web_Services_and_Callouts

サンプルコード
https://github.com/richardvanhook/Force.com-Patterns (英語)
Apexデザインパターン
Apexデザインパターン

More Related Content

What's hot

Salesforce.com Sandbox management
Salesforce.com Sandbox management Salesforce.com Sandbox management
Salesforce.com Sandbox management
Ali Akbar
 
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
Salesforce Developers
 
Performing a successful technical debt assessment in Salesforce
Performing a successful technical debt assessment in SalesforcePerforming a successful technical debt assessment in Salesforce
Performing a successful technical debt assessment in Salesforce
Coforge (Erstwhile WHISHWORKS)
 
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
Salesforce Developers
 
[Final] best practices for access management (mule soft meetups riyadh) - j...
[Final] best practices for access management (mule soft meetups   riyadh) - j...[Final] best practices for access management (mule soft meetups   riyadh) - j...
[Final] best practices for access management (mule soft meetups riyadh) - j...
satyasekhar123
 
Lightning web components
Lightning web componentsLightning web components
Lightning web components
Amit Chaudhary
 
Salesforce Integration Pattern Overview
Salesforce Integration Pattern OverviewSalesforce Integration Pattern Overview
Salesforce Integration Pattern Overview
Dhanik Sahni
 
はじめようLightningコンポーネント
はじめようLightningコンポーネントはじめようLightningコンポーネント
はじめようLightningコンポーネント
Salesforce Developers Japan
 
Power app custom api v0.1.21.1221
Power app custom api v0.1.21.1221Power app custom api v0.1.21.1221
Power app custom api v0.1.21.1221
Ayumu Inaba
 
Salesforce Overview For Beginners/Students
Salesforce Overview For Beginners/StudentsSalesforce Overview For Beginners/Students
Salesforce Overview For Beginners/Students
Sujesh Ramachandran
 
The definitive guide to salesforce sandbox flosum
The definitive guide to salesforce sandbox flosumThe definitive guide to salesforce sandbox flosum
The definitive guide to salesforce sandbox flosum
Flosum
 
Admin Webinar—An Admin's Guide to Profiles & Permissions
Admin Webinar—An Admin's Guide to Profiles & PermissionsAdmin Webinar—An Admin's Guide to Profiles & Permissions
Admin Webinar—An Admin's Guide to Profiles & Permissions
Salesforce Admins
 
Visualforceを使ってみよう
Visualforceを使ってみようVisualforceを使ってみよう
Visualforceを使ってみよう
Salesforce Developers Japan
 
Tackling Salesforce Technical Debt
Tackling Salesforce Technical DebtTackling Salesforce Technical Debt
Tackling Salesforce Technical Debt
panayaofficial
 
Lwc presentation
Lwc presentationLwc presentation
Lwc presentation
Nithesh N
 
Admin Best Practices: Reports & Dashboards
Admin Best Practices: Reports & DashboardsAdmin Best Practices: Reports & Dashboards
Admin Best Practices: Reports & Dashboards
Salesforce Admins
 
Manage Development in Your Org with Salesforce Governance Framework
Manage Development in Your Org with Salesforce Governance FrameworkManage Development in Your Org with Salesforce Governance Framework
Manage Development in Your Org with Salesforce Governance Framework
Salesforce 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 Testing
Salesforce Developers
 
Salesforce Steelbrick CPQ Overview
Salesforce Steelbrick CPQ OverviewSalesforce Steelbrick CPQ Overview
Salesforce Steelbrick CPQ Overview
Harshala Shewale ☁
 
Introduction to lightning Web Component
Introduction to lightning Web ComponentIntroduction to lightning Web Component
Introduction to lightning Web Component
Mohith Shrivastava
 

What's hot (20)

Salesforce.com Sandbox management
Salesforce.com Sandbox management Salesforce.com Sandbox management
Salesforce.com Sandbox management
 
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
 
Performing a successful technical debt assessment in Salesforce
Performing a successful technical debt assessment in SalesforcePerforming a successful technical debt assessment in Salesforce
Performing a successful technical debt assessment in Salesforce
 
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
 
[Final] best practices for access management (mule soft meetups riyadh) - j...
[Final] best practices for access management (mule soft meetups   riyadh) - j...[Final] best practices for access management (mule soft meetups   riyadh) - j...
[Final] best practices for access management (mule soft meetups riyadh) - j...
 
Lightning web components
Lightning web componentsLightning web components
Lightning web components
 
Salesforce Integration Pattern Overview
Salesforce Integration Pattern OverviewSalesforce Integration Pattern Overview
Salesforce Integration Pattern Overview
 
はじめようLightningコンポーネント
はじめようLightningコンポーネントはじめようLightningコンポーネント
はじめようLightningコンポーネント
 
Power app custom api v0.1.21.1221
Power app custom api v0.1.21.1221Power app custom api v0.1.21.1221
Power app custom api v0.1.21.1221
 
Salesforce Overview For Beginners/Students
Salesforce Overview For Beginners/StudentsSalesforce Overview For Beginners/Students
Salesforce Overview For Beginners/Students
 
The definitive guide to salesforce sandbox flosum
The definitive guide to salesforce sandbox flosumThe definitive guide to salesforce sandbox flosum
The definitive guide to salesforce sandbox flosum
 
Admin Webinar—An Admin's Guide to Profiles & Permissions
Admin Webinar—An Admin's Guide to Profiles & PermissionsAdmin Webinar—An Admin's Guide to Profiles & Permissions
Admin Webinar—An Admin's Guide to Profiles & Permissions
 
Visualforceを使ってみよう
Visualforceを使ってみようVisualforceを使ってみよう
Visualforceを使ってみよう
 
Tackling Salesforce Technical Debt
Tackling Salesforce Technical DebtTackling Salesforce Technical Debt
Tackling Salesforce Technical Debt
 
Lwc presentation
Lwc presentationLwc presentation
Lwc presentation
 
Admin Best Practices: Reports & Dashboards
Admin Best Practices: Reports & DashboardsAdmin Best Practices: Reports & Dashboards
Admin Best Practices: Reports & Dashboards
 
Manage Development in Your Org with Salesforce Governance Framework
Manage Development in Your Org with Salesforce Governance FrameworkManage Development in Your Org with Salesforce Governance Framework
Manage Development in Your Org with Salesforce Governance Framework
 
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
 
Salesforce Steelbrick CPQ Overview
Salesforce Steelbrick CPQ OverviewSalesforce Steelbrick CPQ Overview
Salesforce Steelbrick CPQ Overview
 
Introduction to lightning Web Component
Introduction to lightning Web ComponentIntroduction to lightning Web Component
Introduction to lightning Web Component
 

Viewers also liked

インターンシップ成果報告会 発表資料
インターンシップ成果報告会 発表資料インターンシップ成果報告会 発表資料
インターンシップ成果報告会 発表資料
T2C_
 
Spring'16 Apex Code 新機能
Spring'16 Apex Code 新機能Spring'16 Apex Code 新機能
Spring'16 Apex Code 新機能
Taiki Yoshikawa
 
Spring'17リリースノート輪読会 API By フレクト
Spring'17リリースノート輪読会 API By フレクトSpring'17リリースノート輪読会 API By フレクト
Spring'17リリースノート輪読会 API By フレクト
政雄 金森
 
tokyo-salesforce-dg-meetup-2017-etl-with-sphinx
tokyo-salesforce-dg-meetup-2017-etl-with-sphinxtokyo-salesforce-dg-meetup-2017-etl-with-sphinx
tokyo-salesforce-dg-meetup-2017-etl-with-sphinx
shun saito
 
Sf素人が2週間でアプリケーションビルダーに挑戦してみた
Sf素人が2週間でアプリケーションビルダーに挑戦してみたSf素人が2週間でアプリケーションビルダーに挑戦してみた
Sf素人が2週間でアプリケーションビルダーに挑戦してみた
政雄 金森
 
Salesforce Development Best Practices
Salesforce Development Best PracticesSalesforce Development Best Practices
Salesforce Development Best Practices
Vivek Chawla
 
Salesforceの導入で押さえておきたいポイント
Salesforceの導入で押さえておきたいポイントSalesforceの導入で押さえておきたいポイント
Salesforceの導入で押さえておきたいポイント
Taiki Yoshikawa
 
Customizing the salesforce console with the integration toolkit mt
Customizing the salesforce console with the integration toolkit mtCustomizing the salesforce console with the integration toolkit mt
Customizing the salesforce console with the integration toolkit mtSalesforce Developers
 

Viewers also liked (8)

インターンシップ成果報告会 発表資料
インターンシップ成果報告会 発表資料インターンシップ成果報告会 発表資料
インターンシップ成果報告会 発表資料
 
Spring'16 Apex Code 新機能
Spring'16 Apex Code 新機能Spring'16 Apex Code 新機能
Spring'16 Apex Code 新機能
 
Spring'17リリースノート輪読会 API By フレクト
Spring'17リリースノート輪読会 API By フレクトSpring'17リリースノート輪読会 API By フレクト
Spring'17リリースノート輪読会 API By フレクト
 
tokyo-salesforce-dg-meetup-2017-etl-with-sphinx
tokyo-salesforce-dg-meetup-2017-etl-with-sphinxtokyo-salesforce-dg-meetup-2017-etl-with-sphinx
tokyo-salesforce-dg-meetup-2017-etl-with-sphinx
 
Sf素人が2週間でアプリケーションビルダーに挑戦してみた
Sf素人が2週間でアプリケーションビルダーに挑戦してみたSf素人が2週間でアプリケーションビルダーに挑戦してみた
Sf素人が2週間でアプリケーションビルダーに挑戦してみた
 
Salesforce Development Best Practices
Salesforce Development Best PracticesSalesforce Development Best Practices
Salesforce Development Best Practices
 
Salesforceの導入で押さえておきたいポイント
Salesforceの導入で押さえておきたいポイントSalesforceの導入で押さえておきたいポイント
Salesforceの導入で押さえておきたいポイント
 
Customizing the salesforce console with the integration toolkit mt
Customizing the salesforce console with the integration toolkit mtCustomizing the salesforce console with the integration toolkit mt
Customizing the salesforce console with the integration toolkit mt
 

Similar to Apexデザインパターン

Neo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」までNeo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Keiichiro Seida
 
夏サミ2012 [A-2]ソーシャルプラットフォームを使った業務アプリ開発の現場(ソーシャル機能を取り入れたエンタープライズアプリケーション)
夏サミ2012 [A-2]ソーシャルプラットフォームを使った業務アプリ開発の現場(ソーシャル機能を取り入れたエンタープライズアプリケーション)夏サミ2012 [A-2]ソーシャルプラットフォームを使った業務アプリ開発の現場(ソーシャル機能を取り入れたエンタープライズアプリケーション)
夏サミ2012 [A-2]ソーシャルプラットフォームを使った業務アプリ開発の現場(ソーシャル機能を取り入れたエンタープライズアプリケーション)
Akira Kuratani
 
Tech talk salesforce mobile sdk
Tech talk   salesforce mobile sdkTech talk   salesforce mobile sdk
Tech talk salesforce mobile sdkKazuki Nakajima
 
システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方
Chihiro Ito
 
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理土岐 孝平
 
Apexコアデベロッパーセミナー070726 配布用
Apexコアデベロッパーセミナー070726 配布用Apexコアデベロッパーセミナー070726 配布用
Apexコアデベロッパーセミナー070726 配布用
stomita
 
勉強会force#3 iOSアプリ開発
勉強会force#3 iOSアプリ開発勉強会force#3 iOSアプリ開発
勉強会force#3 iOSアプリ開発Kazuki Nakajima
 
CSS2020 Client Policies on keycloak
CSS2020 Client Policies on keycloak CSS2020 Client Policies on keycloak
CSS2020 Client Policies on keycloak
Hitachi, Ltd. OSS Solution Center.
 
ApexトリガのBest Practiceを目指して
ApexトリガのBest Practiceを目指してApexトリガのBest Practiceを目指して
ApexトリガのBest Practiceを目指して
Takahiro Yonei
 
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
Takashi Yahata
 
Data api workshop at Co-Edo
Data api workshop at Co-EdoData api workshop at Co-Edo
Data api workshop at Co-EdoYuji Takayama
 
C#6.0の新機能紹介
C#6.0の新機能紹介C#6.0の新機能紹介
C#6.0の新機能紹介
Kazunori Hamamoto
 
データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回Naoyuki Yamada
 
Entity Framework 5.0 deep dive
Entity Framework 5.0 deep diveEntity Framework 5.0 deep dive
Entity Framework 5.0 deep dive
Atsushi Fukui
 
JavaOne 2015 報告会 @ 東京 「About MVC 1.0 & JSON-P」
JavaOne 2015 報告会 @ 東京 「About MVC 1.0 & JSON-P」JavaOne 2015 報告会 @ 東京 「About MVC 1.0 & JSON-P」
JavaOne 2015 報告会 @ 東京 「About MVC 1.0 & JSON-P」
Hiroyuki Ohnaka
 
初めての Data API CMS どうでしょう - 仙台編 -
初めての Data API   CMS どうでしょう - 仙台編 -初めての Data API   CMS どうでしょう - 仙台編 -
初めての Data API CMS どうでしょう - 仙台編 -
Yuji Takayama
 
AppExchangeパートナー&デベロッパー第2部:20070523版
AppExchangeパートナー&デベロッパー第2部:20070523版AppExchangeパートナー&デベロッパー第2部:20070523版
AppExchangeパートナー&デベロッパー第2部:20070523版
Junichiro Tasaki
 
ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2
増田 亨
 
はじめてのCodeIgniter
はじめてのCodeIgniterはじめてのCodeIgniter
はじめてのCodeIgniter
Yuya Matsushima
 

Similar to Apexデザインパターン (20)

Neo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」までNeo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
 
夏サミ2012 [A-2]ソーシャルプラットフォームを使った業務アプリ開発の現場(ソーシャル機能を取り入れたエンタープライズアプリケーション)
夏サミ2012 [A-2]ソーシャルプラットフォームを使った業務アプリ開発の現場(ソーシャル機能を取り入れたエンタープライズアプリケーション)夏サミ2012 [A-2]ソーシャルプラットフォームを使った業務アプリ開発の現場(ソーシャル機能を取り入れたエンタープライズアプリケーション)
夏サミ2012 [A-2]ソーシャルプラットフォームを使った業務アプリ開発の現場(ソーシャル機能を取り入れたエンタープライズアプリケーション)
 
Tech talk salesforce mobile sdk
Tech talk   salesforce mobile sdkTech talk   salesforce mobile sdk
Tech talk salesforce mobile sdk
 
システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方システムのモダナイズ 落ちても良いアプリの作り方
システムのモダナイズ 落ちても良いアプリの作り方
 
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理
 
Apexコアデベロッパーセミナー070726 配布用
Apexコアデベロッパーセミナー070726 配布用Apexコアデベロッパーセミナー070726 配布用
Apexコアデベロッパーセミナー070726 配布用
 
勉強会force#3 iOSアプリ開発
勉強会force#3 iOSアプリ開発勉強会force#3 iOSアプリ開発
勉強会force#3 iOSアプリ開発
 
CSS2020 Client Policies on keycloak
CSS2020 Client Policies on keycloak CSS2020 Client Policies on keycloak
CSS2020 Client Policies on keycloak
 
ApexトリガのBest Practiceを目指して
ApexトリガのBest Practiceを目指してApexトリガのBest Practiceを目指して
ApexトリガのBest Practiceを目指して
 
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
エンタープライズIT環境での OpenID Connect / SCIM の具体的実装方法 idit2014
 
★2章
★2章★2章
★2章
 
Data api workshop at Co-Edo
Data api workshop at Co-EdoData api workshop at Co-Edo
Data api workshop at Co-Edo
 
C#6.0の新機能紹介
C#6.0の新機能紹介C#6.0の新機能紹介
C#6.0の新機能紹介
 
データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回
 
Entity Framework 5.0 deep dive
Entity Framework 5.0 deep diveEntity Framework 5.0 deep dive
Entity Framework 5.0 deep dive
 
JavaOne 2015 報告会 @ 東京 「About MVC 1.0 & JSON-P」
JavaOne 2015 報告会 @ 東京 「About MVC 1.0 & JSON-P」JavaOne 2015 報告会 @ 東京 「About MVC 1.0 & JSON-P」
JavaOne 2015 報告会 @ 東京 「About MVC 1.0 & JSON-P」
 
初めての Data API CMS どうでしょう - 仙台編 -
初めての Data API   CMS どうでしょう - 仙台編 -初めての Data API   CMS どうでしょう - 仙台編 -
初めての Data API CMS どうでしょう - 仙台編 -
 
AppExchangeパートナー&デベロッパー第2部:20070523版
AppExchangeパートナー&デベロッパー第2部:20070523版AppExchangeパートナー&デベロッパー第2部:20070523版
AppExchangeパートナー&デベロッパー第2部:20070523版
 
ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2ドメイン駆動設計(DDD)の実践Part2
ドメイン駆動設計(DDD)の実践Part2
 
はじめてのCodeIgniter
はじめてのCodeIgniterはじめてのCodeIgniter
はじめてのCodeIgniter
 

More from Salesforce Developers Japan

Salesforce DX の始め方とパートナー様成功事例
Salesforce DX の始め方とパートナー様成功事例Salesforce DX の始め方とパートナー様成功事例
Salesforce DX の始め方とパートナー様成功事例
Salesforce Developers Japan
 
データ連携の新しいカタチ - 変更データキャプチャ/プラットフォームイベントを MuleSoft Anypoint Platform と組み合わせて試してみよう
データ連携の新しいカタチ - 変更データキャプチャ/プラットフォームイベントを MuleSoft Anypoint Platform と組み合わせて試してみようデータ連携の新しいカタチ - 変更データキャプチャ/プラットフォームイベントを MuleSoft Anypoint Platform と組み合わせて試してみよう
データ連携の新しいカタチ - 変更データキャプチャ/プラットフォームイベントを MuleSoft Anypoint Platform と組み合わせて試してみよう
Salesforce Developers Japan
 
Einstein Analyticsでのデータ取り込みと加工
Einstein Analyticsでのデータ取り込みと加工Einstein Analyticsでのデータ取り込みと加工
Einstein Analyticsでのデータ取り込みと加工
Salesforce Developers Japan
 
GMOペパボのエンジニアが語るHeroku活用ノウハウ
GMOペパボのエンジニアが語るHeroku活用ノウハウGMOペパボのエンジニアが語るHeroku活用ノウハウ
GMOペパボのエンジニアが語るHeroku活用ノウハウ
Salesforce Developers Japan
 
Salesforce Big Object 最前線
Salesforce Big Object 最前線Salesforce Big Object 最前線
Salesforce Big Object 最前線
Salesforce Developers Japan
 
Salesforce 開発者向け最新情報 Web セミナー 〜 TrailheaDX での新発表 & Summer '19 リリース新機能 〜
Salesforce 開発者向け最新情報 Web セミナー 〜 TrailheaDX での新発表 & Summer '19 リリース新機能 〜Salesforce 開発者向け最新情報 Web セミナー 〜 TrailheaDX での新発表 & Summer '19 リリース新機能 〜
Salesforce 開発者向け最新情報 Web セミナー 〜 TrailheaDX での新発表 & Summer '19 リリース新機能 〜
Salesforce Developers Japan
 
Einstein Next Best Action を試してみよう
Einstein Next Best Action を試してみようEinstein Next Best Action を試してみよう
Einstein Next Best Action を試してみよう
Salesforce Developers Japan
 
Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発
Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発
Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発
Salesforce Developers Japan
 
Lightning時代のService Cloud概要とカスタマイズ
Lightning時代のService Cloud概要とカスタマイズLightning時代のService Cloud概要とカスタマイズ
Lightning時代のService Cloud概要とカスタマイズ
Salesforce Developers Japan
 
Spring '19リリース開発者向け新機能セミナー
Spring '19リリース開発者向け新機能セミナーSpring '19リリース開発者向け新機能セミナー
Spring '19リリース開発者向け新機能セミナー
Salesforce Developers Japan
 
業務課題の解決に、データ分析・予測結果の活用を - Einstein Discovery / Einstein 予測ビルダーのご紹介 -
業務課題の解決に、データ分析・予測結果の活用を - Einstein Discovery / Einstein 予測ビルダーのご紹介 -業務課題の解決に、データ分析・予測結果の活用を - Einstein Discovery / Einstein 予測ビルダーのご紹介 -
業務課題の解決に、データ分析・予測結果の活用を - Einstein Discovery / Einstein 予測ビルダーのご紹介 -
Salesforce Developers Japan
 
Einstein analyticsdashboardwebinar
Einstein analyticsdashboardwebinarEinstein analyticsdashboardwebinar
Einstein analyticsdashboardwebinar
Salesforce Developers Japan
 
MuleSoft Anypoint Platformのコンセプトとサービス
MuleSoft Anypoint PlatformのコンセプトとサービスMuleSoft Anypoint Platformのコンセプトとサービス
MuleSoft Anypoint Platformのコンセプトとサービス
Salesforce Developers Japan
 
IoTで成功を収めるための製品と戦略 〜 Salesforce IoT 〜
IoTで成功を収めるための製品と戦略 〜 Salesforce IoT 〜IoTで成功を収めるための製品と戦略 〜 Salesforce IoT 〜
IoTで成功を収めるための製品と戦略 〜 Salesforce IoT 〜
Salesforce Developers Japan
 
Heroku seminar winter19
Heroku seminar winter19Heroku seminar winter19
Heroku seminar winter19
Salesforce Developers Japan
 
Dreamforce18 update platform
Dreamforce18 update platformDreamforce18 update platform
Dreamforce18 update platform
Salesforce Developers Japan
 
Winter '19 開発者向け新機能
Winter '19 開発者向け新機能Winter '19 開発者向け新機能
Winter '19 開発者向け新機能
Salesforce Developers Japan
 
Lightning時代のレポート ダッシュボード & Flow 最前線
Lightning時代のレポート ダッシュボード & Flow 最前線Lightning時代のレポート ダッシュボード & Flow 最前線
Lightning時代のレポート ダッシュボード & Flow 最前線
Salesforce Developers Japan
 
Summer18 開発者向け新機能Webセミナー
Summer18 開発者向け新機能WebセミナーSummer18 開発者向け新機能Webセミナー
Summer18 開発者向け新機能Webセミナー
Salesforce Developers Japan
 
使ってみよう、Salesforce Big Object!
使ってみよう、Salesforce Big Object!使ってみよう、Salesforce Big Object!
使ってみよう、Salesforce Big Object!
Salesforce Developers Japan
 

More from Salesforce Developers Japan (20)

Salesforce DX の始め方とパートナー様成功事例
Salesforce DX の始め方とパートナー様成功事例Salesforce DX の始め方とパートナー様成功事例
Salesforce DX の始め方とパートナー様成功事例
 
データ連携の新しいカタチ - 変更データキャプチャ/プラットフォームイベントを MuleSoft Anypoint Platform と組み合わせて試してみよう
データ連携の新しいカタチ - 変更データキャプチャ/プラットフォームイベントを MuleSoft Anypoint Platform と組み合わせて試してみようデータ連携の新しいカタチ - 変更データキャプチャ/プラットフォームイベントを MuleSoft Anypoint Platform と組み合わせて試してみよう
データ連携の新しいカタチ - 変更データキャプチャ/プラットフォームイベントを MuleSoft Anypoint Platform と組み合わせて試してみよう
 
Einstein Analyticsでのデータ取り込みと加工
Einstein Analyticsでのデータ取り込みと加工Einstein Analyticsでのデータ取り込みと加工
Einstein Analyticsでのデータ取り込みと加工
 
GMOペパボのエンジニアが語るHeroku活用ノウハウ
GMOペパボのエンジニアが語るHeroku活用ノウハウGMOペパボのエンジニアが語るHeroku活用ノウハウ
GMOペパボのエンジニアが語るHeroku活用ノウハウ
 
Salesforce Big Object 最前線
Salesforce Big Object 最前線Salesforce Big Object 最前線
Salesforce Big Object 最前線
 
Salesforce 開発者向け最新情報 Web セミナー 〜 TrailheaDX での新発表 & Summer '19 リリース新機能 〜
Salesforce 開発者向け最新情報 Web セミナー 〜 TrailheaDX での新発表 & Summer '19 リリース新機能 〜Salesforce 開発者向け最新情報 Web セミナー 〜 TrailheaDX での新発表 & Summer '19 リリース新機能 〜
Salesforce 開発者向け最新情報 Web セミナー 〜 TrailheaDX での新発表 & Summer '19 リリース新機能 〜
 
Einstein Next Best Action を試してみよう
Einstein Next Best Action を試してみようEinstein Next Best Action を試してみよう
Einstein Next Best Action を試してみよう
 
Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発
Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発
Salesforce DXとLightning Web ComponentsでモダンSalesforceアプリ開発
 
Lightning時代のService Cloud概要とカスタマイズ
Lightning時代のService Cloud概要とカスタマイズLightning時代のService Cloud概要とカスタマイズ
Lightning時代のService Cloud概要とカスタマイズ
 
Spring '19リリース開発者向け新機能セミナー
Spring '19リリース開発者向け新機能セミナーSpring '19リリース開発者向け新機能セミナー
Spring '19リリース開発者向け新機能セミナー
 
業務課題の解決に、データ分析・予測結果の活用を - Einstein Discovery / Einstein 予測ビルダーのご紹介 -
業務課題の解決に、データ分析・予測結果の活用を - Einstein Discovery / Einstein 予測ビルダーのご紹介 -業務課題の解決に、データ分析・予測結果の活用を - Einstein Discovery / Einstein 予測ビルダーのご紹介 -
業務課題の解決に、データ分析・予測結果の活用を - Einstein Discovery / Einstein 予測ビルダーのご紹介 -
 
Einstein analyticsdashboardwebinar
Einstein analyticsdashboardwebinarEinstein analyticsdashboardwebinar
Einstein analyticsdashboardwebinar
 
MuleSoft Anypoint Platformのコンセプトとサービス
MuleSoft Anypoint PlatformのコンセプトとサービスMuleSoft Anypoint Platformのコンセプトとサービス
MuleSoft Anypoint Platformのコンセプトとサービス
 
IoTで成功を収めるための製品と戦略 〜 Salesforce IoT 〜
IoTで成功を収めるための製品と戦略 〜 Salesforce IoT 〜IoTで成功を収めるための製品と戦略 〜 Salesforce IoT 〜
IoTで成功を収めるための製品と戦略 〜 Salesforce IoT 〜
 
Heroku seminar winter19
Heroku seminar winter19Heroku seminar winter19
Heroku seminar winter19
 
Dreamforce18 update platform
Dreamforce18 update platformDreamforce18 update platform
Dreamforce18 update platform
 
Winter '19 開発者向け新機能
Winter '19 開発者向け新機能Winter '19 開発者向け新機能
Winter '19 開発者向け新機能
 
Lightning時代のレポート ダッシュボード & Flow 最前線
Lightning時代のレポート ダッシュボード & Flow 最前線Lightning時代のレポート ダッシュボード & Flow 最前線
Lightning時代のレポート ダッシュボード & Flow 最前線
 
Summer18 開発者向け新機能Webセミナー
Summer18 開発者向け新機能WebセミナーSummer18 開発者向け新機能Webセミナー
Summer18 開発者向け新機能Webセミナー
 
使ってみよう、Salesforce Big Object!
使ってみよう、Salesforce Big Object!使ってみよう、Salesforce Big Object!
使ってみよう、Salesforce Big Object!
 

Recently uploaded

FIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance Osaka Seminar: Welcome Slides.pdfFIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアルLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
CRI Japan, Inc.
 
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
harmonylab
 
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
Matsushita Laboratory
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
Matsushita Laboratory
 
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
Toru Tamaki
 
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdfFIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance
 
FIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance Osaka Seminar: CloudGate.pdfFIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance
 
CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料
Yuuitirou528 default
 
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdfFIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance
 
This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.
chiefujita1
 
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
Fukuoka Institute of Technology
 
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdfFIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance
 
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさJSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
0207sukipio
 

Recently uploaded (14)

FIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance Osaka Seminar: Welcome Slides.pdfFIDO Alliance Osaka Seminar: Welcome Slides.pdf
FIDO Alliance Osaka Seminar: Welcome Slides.pdf
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアルLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
 
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
【DLゼミ】XFeat: Accelerated Features for Lightweight Image Matching
 
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
 
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
 
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdfFIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
FIDO Alliance Osaka Seminar: LY-DOCOMO-KDDI-Mercari Panel.pdf
 
FIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance Osaka Seminar: CloudGate.pdfFIDO Alliance Osaka Seminar: CloudGate.pdf
FIDO Alliance Osaka Seminar: CloudGate.pdf
 
CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料CS集会#13_なるほどわからん通信技術 発表資料
CS集会#13_なるほどわからん通信技術 発表資料
 
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdfFIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
FIDO Alliance Osaka Seminar: NEC & Yubico Panel.pdf
 
This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.
 
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
単腕マニピュレータによる 複数物体の同時組み立ての 基礎的考察 / Basic Approach to Robotic Assembly of Multi...
 
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdfFIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
FIDO Alliance Osaka Seminar: PlayStation Passkey Deployment Case Study.pdf
 
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさJSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
 

Apexデザインパターン

  • 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. セッションの進め⽅方 6 つのデザインパターンを扱う §  問題 §  パターンの概要 §  コード 積極的な発⾔言を歓迎します!
  • 5. 6 つのパターン 1.  ? 2.  ? 3.  ? 4.  ? 5.  ? 6.  ?
  • 6. システム管理理者のビリーの場合 •  Salesforce の管理理を担当して 3 年年 •  コーディングはつい最近始めたばかり •  エラーのせいで落落ち込んでいます Trigger.AccountTrigger: line 3, column 1 System.LimitException: Too many record type describes: 101 •  助けが必要!
  • 7. 問題のコード 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 } •  1 件の Account (取引先) レコードが挿⼊入されたらどうなるか? •  200 件以上の Account が挿⼊入されたら…?
  • 8. ソリューション – Singleton Singleton - instance : Singleton - Singleton() + getInstance() : Singleton
  • 9. コードを書いてみる 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 } •  これは先ほどと同じコード •  変更更点は次のスライドでハイライト表⽰示します
  • 10. コードを書いてみる 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. コードを書いてみる 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 •  メンバー変数、メソッド、ブロックを修飾可能 •  実⾏行行のタイミングは? •  クラスがランタイム環境にロードされるとき •  Java で保持される期間は? •  JVM が実⾏行行されている間 •  Apex では? •  トランザクションが実⾏行行されている間
  • 13. コードを書いてみる 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. コードを書いてみる 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. コードを書いてみる 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. コードを書いてみる 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. 6 つのパターン 1.  Singleton 2.  ? 3.  ? 4.  ? 5.  ? 6.  ?
  • 19. ビリーに提案したコードはこちら 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) すると、ビリーはこんな要件を挙げてきました §  Google マップのほかにも選択肢が必要 §  クライアントコードでプロバイダを選べるようにしたい
  • 20. ソリューション – Strategy Context strategies Strategy Client +operation() +operation() 1 * 構造的なアルゴリズムを定義し、 ConcreteStrategyA ConcreteStrategyB 各アルゴリズムをカプセル化して、 +operation() +operation() 相互に切切り替え可能にする §  Context => Geocoder §  operation() => getLatLong() §  Strategy => GeocodeService §  ConcreteStrategyA => GoogleMapsImpl §  ConcreteStrategyB => MapQuestImpl
  • 21. コードを書いてみる 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 }
  • 25. 6 つのパターン 1.  Singleton 2.  Strategy 3.  ? 4.  ? 5.  ? 6.  ?
  • 26. 次の問題は? Apex で項⽬目を追加せずに、sObject の機能を拡張するにはどうすればよいか? 処理理の途中で選択の チェックボックスを表⽰示 更更新にもとづいて 項⽬目の値を計算
  • 27. ソリューション – sObject Decorator sObject + Save() ... Concrete sObject sObjectDecorator + Field1 VF + sObj: sObject + Field2 Controller + Property : type ... + Fieldn + sObjectDecorator(sObject) + Operation() + Save() ... (「ラッパークラス」と呼ばれる)
  • 28. サンプルのシナリオ 天気の情報を格納する sObject 「Weather」 §  「City__c」(市) §  「TempInFahrenheit__c」(華⽒氏換算の気温) Visualforce ページ作成にあたっての要件 §  Temperature レコードに格納されている華⽒氏の気温データを、摂⽒氏で表⽰示する §  Temperature レコードに摂⽒氏で⼊入⼒力力される気温データを、華⽒氏のデータとして保存する 双⽅方向で データを換算して表⽰示
  • 29. コード – Decorator による sObject クラスの拡張 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. コード – カスタムコントローラ 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. コード – Visualforce ページ 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>
  • 33. 6 つのパターン 1.  Singleton 2.  Strategy 3.  sObject Decorater 4.  ? 5.  ? 6.  ?
  • 34. このコードの問題は? Visualforce コントローラ 1 Visualforce コントローラ 2 Visualforce コントローラ 3
  • 35. ソリューション – Façade 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. サンプルのシナリオ Customer (顧客) レコードを作成する、複数の処理理から成るトランザクション §  CreateAccount Web サービス – 取引先レコードを作成 §  CreateContact Web サービス – 取引先責任者レコードを作成 ⼊入⼒力力 §  UserId – 現在のユーザ §  Timestamp – 現在のタイムスタンプ §  Name – 取引先名 (⼤大⽂文字に変換) §  LastName、FirstName – 取引先責任者の姓、名 その他に設定すべき項⽬目 §  Timeout – タイムアウト値 §  Hostname – ホスト名 リモートシステムから取引先と取引先責任者の追跡番号が返される
  • 37. コード – Façade クラス 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. コード – Façade クラス 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. コード – クライアント 01 public class FooController{ 02 03 public Account account { get; set; } 04 public Contact contact { get; set; } 05 … public void CallCreateCustomerWS() { 06 CreateCustomerFacade ca = 07 new CreateCustomerFacade(); 08 09 CreateCustomerFacade.CreateCustomerResponse resp = 10 ca.CreateCustomerExternal(account.name, 11 contact.LastName, contact.FirstName); 12 13 account.accountNumber = resp.accountNumber; 14 contact.contactNumber__c = resp.contactNumber; 15 } }
  • 40. 6 つのパターン 1.  Singleton 2.  Strategy 3.  sObject Decorater 4.  Façade 5.  ? 6.  ?
  • 41. 式をどうやって表現するか? 1 AND 2 1 OR (2 AND 3) (1 AND 2) OR ((3 OR 4) AND 5)
  • 42. ソリューション – 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. コードを書いてみる 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. 式を作成する 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. 式の使⽤用例例 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. 6 つのパターン 1.  Singleton 2.  Strategy 3.  sObject Decorater 4.  Façade 5.  Composite 6.  ?
  • 48. ビリーが新たな問題に直⾯面しています Opportunity (商談) レコードがクローズされたタイミングで Order (注⽂文) レコードを作成するトリガを記述したつもりだったが… §  クローズ済みの商談レコードが更更新されるたびに注⽂文レコードが作成されてしまう §  Apex データローダを使ってインポートを実⾏行行した場合に、 クローズ済みの商談レコードの⼀一部で注⽂文レコードが作成されないことがある
  • 49. 問題のコード 01 trigger OpptyTrigger on Opportunity (after insert, after update) { 02 03 if (trigger.new[0].isClosed) { 04 Order__c order = new Order__c(); 05 … 前の状態がどうであるかに 関係なく実⾏行行される 06 insert order 07 } バルク処理理に 08 } 対応していない 再利利⽤用性が低い
  • 50. こうしたらどうか? 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 ... 08 insert order; 前の状態がどうであるかに 関係なく実⾏行行される 09 } 10 } 11 12 } バルク処理理に 13 } 対応していない
  • 51. ではこうしたら? 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 Order__c order = new Order__c(); OK  になった 10 ... 11 orderList.add(order); 12 } コードのコンテキスト依存度度が 13 } ⾼高く、再利利⽤用が難しい 14 insert orderList ; 15 }
  • 52. ソリューション – "Bulk State Transition" (バルク状態遷移) Utility Class Trigger + Foo(sObject[]) •  状態が変更更されたレコードの中で、 •  あらゆるコンテキストから 条件に⼀一致するものを検出 呼び出せるユーティリティクラスの •  所定の処理理を実⾏行行するユーティリティ 汎⽤用的なメソッド クラスのメソッドを呼び出す •  条件を満たすレコードのみを ユーティリティクラスに渡す
  • 53. これで問題解決!!! 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))) トリガが状態遷移を 08 closedOpptyList.add(oppty); 適切切に処理理 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 ... 再利利⽤用性が⾼高まり、 07 orderList.add(order); バルク処理理にも対応 08 } 09 insert orderList ;
  • 54. 6 つのパターン 1.  Singleton 2.  Strategy 3.  sObject Decorater 4.  Façade 5.  Composite 6.  Bulk State Transition
  • 55. 関連リソース ラッパークラス http://wiki.developerforce.com/page/Wrapper_Class (英語) Apex コードに関するベストプラクティス http://wiki.developerforce.com/page/Apex_Code_Best_Practices (英語) Apex の Web サービスとコールアウト http://wiki.developerforce.com/page/JP:Apex_Web_Services_and_Callouts サンプルコード https://github.com/richardvanhook/Force.com-Patterns (英語)