Decorator Pattern

design-pattern-hdr_img2
The Decorator Pattern is very useful pattern to extend your application more flexible.
Usually, a factory pattern, only one class will be invoked, but by using decorator pattern, you can invoice more than one classes in one call.

public interface RtrnAdjustService {

	List<Map<String, Object>> getRmaLineToBeAdjustd();
	List<Map<String, Object>> getRmaLineToBeAdjustd(RCV_RPT_LINETMsg rrLnTMsg);
	void adjustRma(List<Map<String, Object>> rmaLineToBeAdjustd, RCV_RPT_LINETMsg rrLnTMsg) throws RRException;
}

Above: Interface

public class AWBL1050AdjustStaticFactory {

	private AWBL1050AdjustStaticFactory() {
		// Prevent non-static instantiation
	}

	public static RtrnAdjustService getObj(AWBL1050CMsg bizMsg, List<Map<String, Object>> rmaLineToBeAdjustd, RCV_RPT_LINETMsg rrLnTMsg) throws RRException {

		RtrnAdjustServiceModel model = creteModel(bizMsg);
		// 1st invoike
		model.setRmaLineStsCd(RMA_LINE_STS.CANCELLED);
		RtrnAdjustService svc = new RtrnAdjustServiceImplByRmaBase(model);
		/** RMA qty need to be added for Non-Crushed line */
		svc.adjustRma(rmaLineToBeAdjustd, rrLnTMsg);

		/** Decolator Pattern (After first ajust) */
		// 2nd invoice
		return new RtrnAdjustServiceImplRmaQty(svc, model);
	}
}

Above: Factory call:

public class RtrnAdjustServiceImplByRmaBase implements RtrnAdjustService, AWBL1050Constant {

	protected RtrnAdjustServiceImplByRmaBase(RtrnAdjustServiceModel model) {
		this.model = model;
	}

	public List<Map<String, Object>> getRmaLineToBeAdjustd() {
		// Since RR line is not specified, the entire RR is a target
		return new List<Map<String, Object>>();
	}

	public void adjustRma(List<Map<String, Object>> rmaLineToBeAdjustd, RCV_RPT_LINETMsg rrLnTMsg) throws RRException {
		// do something
	}
}

Above: 1st class to be invoked

public class RtrnAdjustServiceImplRmaQty extends RtrnAdjustServiceDecolator implements AWBL1050Constant {

	protected RtrnAdjustServiceImplRmaQty(RtrnAdjustService svc, RtrnAdjustServiceModel model) {
		super(svc);
		this.model = model;
	}

	public List<Map<String, Object>> getRmaLineToBeAdjustd() {
		return new ArrayList<Map<String, Object>>(); // Return empty list
	}

	public List<Map<String, Object>> getRmaLineToBeAdjustd(RCV_RPT_LINETMsg rrLnTMsg) {
		return new ArrayList<Map<String, Object>>(); // Return empty list
	}

	@Override
	public void adjustRma(List<Map<String, Object>> rmaLineToBeAdjustd, RCV_RPT_LINETMsg rrLnTMsg) throws RRException {
		// do something
	}
}

Above: 2nd class to be invoked

The factory class call two class by one call, so you don’t need to change any code from main class that call the method.

public abstract class RtrnAdjustServiceDecolator implements RtrnAdjustService {

	protected RtrnAdjustService svc;
	
	protected RtrnAdjustServiceDecolator(RtrnAdjustService svc) {
		this.svc = svc;
	}

	public abstract void adjustRma(List<Map<String, Object>> rmaLineToBeAdjustd, RCV_RPT_LINETMsg rrLnTMsg) throws RRException;
}

Above: Abstract class for 2nd class

RtrnAdjustService svc = AWBL1050AdjustStaticFactory.getObj(bizMsg);
List<Map<String, Object>> rmaLineToBeAdjustd = svc.getRmaLineToBeAdjustd();
.
.
/** Calling by factory */
svc = AWBL1050AdjustStaticFactory.getObj(bizMsg, rmaLineToBeAdjustd, rrLnTMsg);
/** Method call */
svc.adjustRma(rmaLineToBeAdjustd, rrLnTMsg);
.

Above: class and method call from such as main method

Static Factory Pattern

design-pattern-hdr_img2
It is always good to use Design Pattern in your application, although it is not required, in order to avoid spaghetti. One of popular design pattern is Factory pattern. The concept is similar to DI (Dependency Injection). In this example, I use Static Factory pattern.
stat-facto-pattern-diagram1
With Factory pattern, you can instantiate a class with “new” (Source Code)

@RequestMapping("/cUrlValSubLine01Jsp/{rmaNum}")
public ModelAndView goToSubLine01Jsp(@PathVariable("rmaNum") String rmaNum,	Model model, HttpServletRequest req) {
	List<RmaLineModel> rmaLineModelList = RmaDtlBL.getRmaLineListWithCdTblNm(rmaNum, null);
	return getMVSubLine01(rmaNum, rmaLineModelList, req);
}

This method is being called to set ModelAndView object, and one of them is the list of code for auto-complete feature

private ModelAndView getMVSubLine01(String rmaNum, List<RmaLineModel> rmaLinsList, HttpServletRequest req) {

	RmaLineListModel newModel = new RmaLineListModel(rmaNum, rmaLinsList);

	ModelAndView modelAndView = new ModelAndView(VIEW.SUB_LINE_01.getVal());
	modelAndView.addObject(CONST.FORM_KEY.getVal(), newModel);
	// For item detail list
	modelAndView.addObject(CONST.LINE_LIST_MODEL.getVal(), newModel);
	// Setup Status drop down line the item list
	modelAndView.addObject(CONST.HDR_STS_LIST.getVal(), getList(CONST.HDR_STS_LIST.getVal()));
	// Item list for AJAX Auto complete
	req.getSession().setAttribute(CONST.MDSE_LIST.getVal(), getList(CONST.MDSE_LIST.getVal()));
	return modelAndView;
}

Above line 12 calls this method:

private List<?> getList(String key) {
	BLFactory fact = BLFactory.getInstance(key);
	return fact.getList();
}

Above line 12 calls this method:

package com.ns.spring.common.gen;

import java.util.List;

import com.ns.spring.constant.RtrnConstant;

public class BLFactory implements RtrnConstant {

	private BLService svc;

	private BLFactory(String param) {
		if (CONST.HDR_STS_LIST.getVal().equals(param)) {
			this.svc = new RtrnCommonBL();
		} else if (CONST.TP_LIST.getVal().equals(param)) {
			this.svc = new TpCommonBL();
		} else if (CONST.MDSE_LIST.getVal().equals(param)) {
			this.svc = new MdseCommonBL();
		}
	}

	// static factory
	public static BLFactory getInstance(String param) {
		return new BLFactory(param);
	}

	public List<?> getList() {
		return this.svc.getList();
	}
}

This factory class returns static instance via interface BLService.

package com.ns.spring.common.gen;

import java.util.List;

public interface BLService {
	public List<?> getList();
}
package com.ns.spring.common.gen;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.ns.spring.common.CommonBL;
import com.ns.spring.constant.RtrnConstant.CONST;
import com.ns.spring.model.MDSE;
import com.ns.spring.model.RMA_HDR_STS;
import com.ns.spring.model.RTRN_TP;
import com.ns.spring.model.ui.MdseModel;
import com.ns.spring.model.ui.RmaHdrStsModel;
import com.ns.spring.model.ui.RtrnTpModel;
import com.ns.spring.service.template.MdseService;
import com.ns.spring.service.template.RmaHdrStsService;
import com.ns.spring.service.template.RtrnTpService;

@Component
public class MdseCommonBL implements BLService {

	private static MdseService mdseSvc;
	
	@Autowired(required = true)
	public void setMdseSvc(MdseService mdseSvc) {
		this.mdseSvc = mdseSvc;
	}

	@Override
	public List<MdseModel> getList() {
		List<MdseModel> mdseModelList = new ArrayList<>();
		List<MDSE> mdseList = mdseSvc.findAll();
		if (!CommonBL.isEmpty(mdseList)) {
			for (int i = 0; i < mdseList.size(); i++) {
				MDSE obj = (MDSE) mdseList.get(i);
				mdseModelList.add(new MdseModel(i, obj.getMdseCd()));
			}
		}
		return mdseModelList;
	}
}

getList() eventually calls findAll() that returns all record from MDSE table.