【Fiori】Dynamic Page, Semantic Page, Object Pageを比較する

##目的
Fioriで1ページの画面を作るときに使う代表的な3つのレイアウトを実装し、実装の手間やわかりやすさなどを比較してみます。
関連記事：[【Fiori】2つの基本的なレイアウトについて](https://qiita.com/tami/items/c1ff0709661467ca2c9d)

**紹介するレイアウト**

- Dynamic Page
- Semantic Page
- Object Page

##3つのレイアウトの構成
SAPUI5 version: 1.73.1の[API Reference](https://sapui5.hana.ondemand.com/#/api)をもとに、それぞれのレイアウトがどのようなaggregation（パーツ）から構成されているかを図に表しました。全てのaggregationではなく、代表的と思われるものだけ載せています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/4b119a9b-1e17-5aa1-b614-83f0fe069edb.png)

###Dynamic Page
ヘッダー、コンテンツ、フッターから構成される基本のレイアウトです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/87c4ac98-1752-61b3-eb65-edd3f5873a05.png)


###Semantic Page
aggregationの種類が多く、36種類もあります。aggregationによって画面のどこに表示されるかが自動的に決まります。たとえばDelete、Copyなどのボタンごとにaggregationが用意されており、DeleteはCopyより左に来ることも決まっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/3f14b4a0-452e-d173-7dd1-52aff795f5c5.png)

###Object Page
ヘッダ部分はDynamic Pageと同じですが、コンテンツにあたるsectionが入れ子の構造になっています。ObjectPageSectionが一番外側で、この単位でアンカーバーと呼ばれるタブのようなものがつきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/6e9cdd92-c7d7-8e56-1f56-a7ccb066633e.png)

ObjectPageSectionと画面の対応は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/4a5e68b1-91f4-4d00-bdc8-49ac74505c25.png)


##実装してみた
比較のため、同じ画面パーツ（フラグメント）を使って3つの画面を実装してみました。
ソースは以下にあります。
https://github.com/miyasuta/LayoutSample

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/f2647627-1596-4de4-ee02-0ce40b80ec35.png)

###ビューの実装
####Dynamic Page
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/91e81953-786d-fbea-c5d3-1a339488ecf1.png)

```xml:DynamicPage.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
	xmlns:f="sap.f"
	xmlns:l="sap.ui.layout"
	controllerName="demo.Train_20_LayoutSample.controller.DynamicPage" xmlns:html="http://www.w3.org/1999/xhtml">

	<f:DynamicPage id="dynamicPage" headerExpanded="true" showFooter="true">
		<f:title>
			<f:DynamicPageTitle>
				<f:heading>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Heading" type="XML" />
				</f:heading>
				<f:content>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.TitleContent" type="XML" />
				</f:content>
				<f:actions>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Actions" type="XML" />
				</f:actions>
				<f:breadcrumbs>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Breadcrumbs" type="XML" />
				</f:breadcrumbs>
				<f:navigationActions>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.NavigationActions" type="XML" />               
				</f:navigationActions>				
			</f:DynamicPageTitle>
		</f:title>
		
		<f:header>
			<f:DynamicPageHeader pinnable="true">
				<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.HeaderContent" type="XML" />
			</f:DynamicPageHeader>
		</f:header>
		
		<f:content>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.MainContent" type="XML" />
		</f:content>
		
		<f:footer>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.FooterActions" type="XML" />
		</f:footer>
	</f:DynamicPage>

</mvc:View>
```

####Semantic Page
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/fbafa7e4-39f4-fdc2-8bb8-e7ace312bd2c.png)

```xml:SemanticPage.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
	xmlns:l="sap.ui.layout"
	xmlns:semantic="sap.f.semantic"
	controllerName="demo.Train_20_LayoutSample.controller.SemanticPage" xmlns:html="http://www.w3.org/1999/xhtml">
	
	<semantic:SemanticPage id="semanticPage" headerPinnable="true" showFooter="true">
		<semantic:titleHeading>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Heading" type="XML" />
		</semantic:titleHeading>
		
		<semantic:titleContent>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.TitleContent" type="XML" />
		</semantic:titleContent>
		
		<semantic:headerContent>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.HeaderContent" type="XML" />
		</semantic:headerContent>
		
		<semantic:content>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.MainContent" type="XML" />
		</semantic:content>

		<semantic:titleBreadcrumbs>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Breadcrumbs" type="XML" />
		</semantic:titleBreadcrumbs>
		
		<!--Header actions-->
		<semantic:titleMainAction>
			<semantic:TitleMainAction text="Edit"/>
		</semantic:titleMainAction>
		
		<semantic:titleCustomTextActions>
			<Button text="Toggle Footer" press="onToggleFooter" />
		</semantic:titleCustomTextActions>

		<semantic:copyAction>
			<semantic:CopyAction />
		</semantic:copyAction>
		
		<semantic:deleteAction>
			<semantic:DeleteAction />
		</semantic:deleteAction>
		
		<!--Navigation actions-->
		<semantic:fullScreenAction>
			<semantic:FullScreenAction press="onFullScreen" visible="{= ${/actionButtonsInfo/midColumn/fullScreen} !== null }"/>
		</semantic:fullScreenAction>

		<semantic:exitFullScreenAction>
			<semantic:ExitFullScreenAction press="onExitFullScreen" visible="{= ${/actionButtonsInfo/midColumn/exitFullScreen} !== null }" />
		</semantic:exitFullScreenAction>
		
		<semantic:closeAction>
			<semantic:CloseAction press="onClose" visible="{= ${/actionButtonsInfo/midColumn/closeColumn} !== null }" />
		</semantic:closeAction>		
		
		<!--Footer actions-->
		<semantic:messagesIndicator>
			<semantic:MessagesIndicator press="onMessagesButtonPress"/>
		</semantic:messagesIndicator>
		
		<semantic:positiveAction>
			<semantic:PositiveAction />
		</semantic:positiveAction>
		
		<semantic:negativeAction>
			<semantic:NegativeAction />
		</semantic:negativeAction>		
		
		<semantic:footerCustomActions>
		</semantic:footerCustomActions>
		
	</semantic:SemanticPage>
	
</mvc:View>
```
####Object Page
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276021/844d1181-e490-687f-a289-61d8f39c3f72.png)

```xml:ObjectPage.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
	xmlns:l="sap.ui.layout"
	xmlns:uxap="sap.uxap"
	controllerName="demo.Train_20_LayoutSample.controller.ObjectPage" xmlns:html="http://www.w3.org/1999/xhtml">

	<uxap:ObjectPageLayout id="objectPage" showFooter="true">
		<uxap:headerTitle>
			<uxap:ObjectPageDynamicHeaderTitle>
				<uxap:heading>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Heading" type="XML" />
				</uxap:heading>
				<uxap:content>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.TitleContent" type="XML" />
				</uxap:content>
				<uxap:actions>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Actions" type="XML" />
				</uxap:actions>
				<uxap:breadcrumbs>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Breadcrumbs" type="XML" />
				</uxap:breadcrumbs>
				<uxap:navigationActions>
					<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.NavigationActions" type="XML" />
				</uxap:navigationActions>				
			</uxap:ObjectPageDynamicHeaderTitle>
			
		</uxap:headerTitle>
		
		<uxap:headerContent>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.HeaderContent" type="XML" />
		</uxap:headerContent>
		
		<uxap:sections>
			<uxap:ObjectPageSection title="Product">
				<uxap:subSections>
					<uxap:ObjectPageSubSection title="">
						<uxap:blocks>
							<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Product" type="XML" />
						</uxap:blocks>
					</uxap:ObjectPageSubSection>
				</uxap:subSections>
			</uxap:ObjectPageSection>
			
			<uxap:ObjectPageSection title="Customer">
				<uxap:subSections>
					<uxap:ObjectPageSubSection title="">
						<uxap:blocks>
							<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.Customer" type="XML" />
						</uxap:blocks>
					</uxap:ObjectPageSubSection>
				</uxap:subSections>
			</uxap:ObjectPageSection>			
		</uxap:sections>
		
		<uxap:footer>
			<core:Fragment fragmentName="demo.Train_20_LayoutSample.fragment.FooterActions" type="XML" />
		</uxap:footer>
		
	</uxap:ObjectPageLayout>

</mvc:View>
```
###同じ画面を作るのに要した行数
XMLビューの行数（スペースを除く）をカウントしてみました。

**結果**

- Dynamic Page: 40行
- Semantic Page: 69行
- Object Page: 58行

Semantic Pageは表示する項目ごとにaggregationが分かれるので、必然的に行数が多くなります。

##まとめ
実装してみて感じた各レイアウトのメリット、デメリットは以下です。

| レイアウト       |メリット |デメリット、留意点    |
|:-----------------|:------------------|:------------------|
| Dynamic Page|シンプルで実装しやすい。項目の配置の自由度が高い |ボタンの配置などについてプロジェクトで統一したルールを作ることが必要        |
| Semantic Page           |出力位置が自動的に決まるので、一貫したレイアウトになる |多数あるaggregationを使い分ける必要がある。ビューをぱっと見たときにどのような画面になるのか想像しにくい       |
| Object Page           |コンテンツをグループ化してセクションを作れるので、多数の項目を出す画面に向いている|Dynamic Pageと同様|