PR

Switch文使用

広告

サンプルコード

AnimalController.java

package com.example.demo.controller.animal;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.example.demo.entity.AnimalKindsEntity;
import com.example.demo.form.AnimalForm;
import com.example.demo.service.animal.AnimalService;

import lombok.RequiredArgsConstructor;

/** switch文を使用した分岐コントローラー */
@Controller
@RequiredArgsConstructor
@RequestMapping("/animal")
public final class AnimalController
{

	private final AnimalService animalService;

	// ==== ModelAttribute ====

	@ModelAttribute("animals")
	public Map<String, String> animals()
	{
		final List<AnimalKindsEntity>   animal_kinds = animalService.getAllAnimalKindsData();
		final Map<String, String> animals = new TreeMap<String, String>();
		for (final AnimalKindsEntity animal_kind : animal_kinds)
		{
			animals.put(animal_kind.getId().toString(), animal_kind.getName());
		}
		return animals;
	}

	@ModelAttribute("form")
	public AnimalForm form()
	{
		return new AnimalForm("", null, Collections.emptyList());
	}

	@ModelAttribute("display")
	public String display()
	{
		return "display";
	}

	@ModelAttribute("clear")
	public String clear()
	{
		return "clear";
	}

	@ModelAttribute("action")
	public String action()
	{
		return "/animal/submit";
	}

	// ==========================


	/** 初期表示 */
	@GetMapping("/index")
	public String index(final Model model)
	{
		model.addAttribute("test", "初期表示");
		return "animal";
	}

	@PostMapping("/submit")
	public String execute(
			@RequestParam final String action,
			@ModelAttribute("form") final AnimalForm animalForm,
			final BindingResult error,
			final Model model
			)
	{
		model.addAttribute("form", animalForm);

		// 押されたボタンにより、処理を分岐
		switch (action)
		{
			case "display": // 表示ボタン
				animalService.display(model);
				break;
			case "clear": // 画面クリアボタン
				animalService.clear(model);
				break;
			default: // 初期表示ボタン
				return "redirect:/animal/index";
		}

		return "animal";
	}
}

AnimalService.java

package com.example.demo.service.animal;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;

import com.example.demo.entity.AnimalKindsEntity;
import com.example.demo.entity.AnimalNameEntity;
import com.example.demo.form.AnimalForm;
import com.example.demo.repository.AnimalKindsRepository;
import com.example.demo.repository.AnimalNameRepository;
import lombok.RequiredArgsConstructor;

/** switch文を使用した分岐のサービスクラス */
@Service
@RequiredArgsConstructor
public final class AnimalService
{
	@Autowired
	private Validator springValidator;

	private final AnimalKindsRepository animalKindsRepository;
	private final AnimalNameRepository  animalNameRepository;

	/** 表示ボタン押下時の処理 */
	public void display(final Model model)
	{
		final AnimalForm form = (AnimalForm) model.getAttribute("form");

		switch (form.getAnimalAsInt())
		{
			case 1:
				model.addAttribute("test", "ねこ表示");
				break;
			case 2:
				model.addAttribute("test", "いぬ表示");
				break;
			case 3:
				model.addAttribute("test", "さる表示");
				break;
		}

		final BindingResult bindingResult = new BeanPropertyBindingResult(form, "form");
		if (!validation(model, form, bindingResult))
		{
			return;
		}

		final Optional<AnimalKindsEntity> kinds_data     = getSelectedKindsData(model, bindingResult, form);
		if (kinds_data.isEmpty())
		{
			return;
		}

		final List<AnimalNameEntity> name_data = animalNameRepository.findByPrimaryKeysKindsId(form.getAnimalAsInt());

		form.setKinds_data(kinds_data.get());
		form.setName_data(name_data);
		model.addAttribute("form", form);
	}

	private Optional<AnimalKindsEntity> getSelectedKindsData(
			final Model model, final BindingResult bindingResult, final AnimalForm form
			)
	{
		final Optional<AnimalKindsEntity> kinds_data = animalKindsRepository.findById(form.getAnimalAsInt());

		if (!kinds_data.isPresent())
		{
			bindingResult.rejectValue("animal", "form.animal.notexist");
			model.addAttribute("org.springframework.validation.BindingResult.form", bindingResult);
			return Optional.empty();
		}
		return kinds_data;
	}

	private boolean validation(final Model model, final AnimalForm form, final BindingResult bindingResult)
	{
		springValidator.validate(form, bindingResult);

		if (bindingResult.hasErrors())
		{
			model.addAttribute("org.springframework.validation.BindingResult.form", bindingResult);
			return false;
		}

		return true;
	}

	/** 画面クリアボタン押下時の処理 */
	public void clear(final Model model)
	{
		final AnimalForm form = (AnimalForm) model.getAttribute("form");

		switch (form.getAnimalAsInt())
		{
			case 1:
				model.addAttribute("test", "ねこ画面クリア");
				break;
			case 2:
				model.addAttribute("test", "いぬ画面クリア");
				break;
			case 3:
				model.addAttribute("test", "さる画面クリア");
				break;
		}

		form.setKinds_data(null);
		form.setName_data(Collections.emptyList());
	}

	/**
	 * 画面表示ModelAttribute用
	 *
	 * @return {@code List<AnimalKindsEntity>} animal_kindsテーブルの全データ
	 */
	public List<AnimalKindsEntity> getAllAnimalKindsData()
	{
		return animalKindsRepository.findAll();
	}

}

詳細説明

画面から、何かボタンが押された際、
Controllerにて設定された(52~62行目)値がactionというキーで飛んできます。

それを92行目のswitch文で分岐し、Serviceクラスの処理を実行しています。

switch文使用のメリット

  • ファイルが少なく済む

switch文使用のデメリット

  • 冗長になりやすい
  • 修正にあまり強くない

デメリットの修正に強くないとはどういうことか。

サンプルコードには、AnimalServiceクラスの37~48行目や102~113行目に同様の条件のswitch文があります。

もし、仕様変更やデータ追加で、例えば「とり」が追加されたとします。

そうすると、この2つのswitch文を修正する必要が出てきます。

今回のサンプルでは、2つしかないので、修正漏れは出にくいかと思いますが、
このような同様の条件のswitch文が複数個所出てくる場合があります。

そうすると、修正漏れが出やすくなり、バグの原因となります。

swtich文なので、コンパイルエラーなども出ず、バグに気が付かずにリリースされたら大変なことになるでしょう。

一概にswitch文が悪いとは言いませんが、使用するのであれば、複数個所で使用される可能性が低い場合に使用するか、修正の際に細心の注意を払ってすることが必要でしょう。

このデメリットを解消してくれるのがinterfaceの使用です。

ぜひサンプルコードをご覧ください。

参考書

広告
タイトルとURLをコピーしました