7
\$\begingroup\$

In my project, I have 3 payment mode. Via Manually Entered , Card Swipe, and cash. I have 2 fragments named RecordCardManuallyFragment and SwipeCadFragment and they both are almost identical according to functionality except in RecordCardManually you have to type info manually and in swipe card fragment you informaion gets filled on the form automatically.

One of my friends says it would have been good if you have kept in a single file rather than 2 separate files, because when there is a change you will have to change in either files. But I kept them separate because of the Single Responsibility Principle of object-oriented design.

So how could I make my code better and effective accordingly with the Strategy design pattern?

public class RecordCardManuallyFragment extends BaseFragment implements View.OnFocusChangeListener {

    private View view;
    private TextView tvTotal, tvTotalAmount, tvCardInfo, tvNameOnCard, tvCardNumber, tvCardExpiration, tvCVV;
    private TextView btnRecordPayment;
    private TextView etExpiryDate;
    private EditText etNameOnCard, etCardNumber, etCvv;
    private RelativeLayout layoutCardNumber;
    private CardInformationModel cardInformationModel;

    public RecordCardManuallyFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        view = inflater.inflate(R.layout.fragment_record_card_manually, container, false);
        initViews();
        setClickListener();
        setCustomFonts();
        setValuesToUIFromSession();
        ((HomeActivity) getActivity()).visibilityOfCounter(false);
        ((HomeActivity) getActivity()).setVisibilityOfEditIcon(false);

        return view;
    }

    private void setValuesToUIFromSession() {
        double amount = session.getUserCart().getAmount();
        String formattedAmount = String.format("%.2f", amount);
        tvTotalAmount.setText("$" + formattedAmount);
        CardInformationModel cardInformationModel = session.getUserCart().getCardInformationModel();
        if (cardInformationModel != null) {
            etNameOnCard.setText(cardInformationModel.getNameOnCard());
            etCardNumber.setText(String.valueOf(cardInformationModel.getNumberOnCard()));
            etExpiryDate.setText(cardInformationModel.getExpirationDate());
            etCvv.setText(String.valueOf(cardInformationModel.getCvv()));
        }
    }

    private void setCustomFonts() {
        iCannPayUtils.setCustomFontToTextView(getActivity(), tvTotal, Constants.FUTURA_BOOK);
        iCannPayUtils.setCustomFontToTextView(getActivity(), tvTotalAmount, Constants.FUTURA_BOOK);
        iCannPayUtils.setCustomFontToTextView(getActivity(), tvCardInfo, Constants.FUTURA_BOOK_BOLD);
    }

    private void setClickListener() {
        btnRecordPayment.setOnClickListener(this);
        tvNameOnCard.setOnClickListener(this);
        tvCardNumber.setOnClickListener(this);
        tvCardExpiration.setOnClickListener(this);
        tvCVV.setOnClickListener(this);
        etExpiryDate.setOnClickListener(this);
        etNameOnCard.setOnFocusChangeListener(this);
        etCardNumber.setOnFocusChangeListener(this);
        etCvv.setOnFocusChangeListener(this);
    }

    private void initViews() {
        tvTotal = (TextView) view.findViewById(R.id.tv_total);
        tvTotalAmount = (TextView) view.findViewById(R.id.tv_total_amount);
        tvCardInfo = (TextView) view.findViewById(R.id.tv_sign_receipt);
        btnRecordPayment = (TextView) view.findViewById(R.id.btn_record_payment);
        etExpiryDate = (TextView) view.findViewById(R.id.et_expiration_date);
        etNameOnCard = (EditText) view.findViewById(R.id.et_name_on_card);
        etCardNumber = (EditText) view.findViewById(R.id.et_card_number);
        etCvv = (EditText) view.findViewById(R.id.et_scc);
        layoutCardNumber = (RelativeLayout) view.findViewById(R.id.layout_card_number);
        tvNameOnCard = (TextView) view.findViewById(R.id.tv_name_card);
        tvCardExpiration = (TextView) view.findViewById(R.id.tv_expiration_date);
        tvCardNumber = (TextView) view.findViewById(R.id.tv_card_number);
        tvCVV = (TextView) view.findViewById(R.id.tv_cvv);
    }

    @Override
    public String getName() {
        return "Record Card Manually";
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_record_payment:
                if (validateAllFields()) {
                    fillCardInformationModel();
                    session.getUserCart().setCardInformationModel(cardInformationModel);
                    createOrder();
                }
                break;

            case R.id.et_expiration_date:
                showDatePickerDialog(new IDatePickerListener() {
                    @Override
                    public void afterSetDate(int year, int month, int day) {
                        String s = String.format("%d/%d", month + 1, year);
                        etExpiryDate.setText(s);
                    }
                });
                break;

            case R.id.tv_card_number:
                etCardNumber.requestFocus();
                break;

            case R.id.tv_name_card:
                etNameOnCard.requestFocus();
                break;

            case R.id.tv_expiration_date:
                break;

            case R.id.tv_cvv:
                etCvv.requestFocus();
                break;
        }

    }

    private void createOrder() {
        Dialogs.showProgressDialog(getActivity(), layoutCardNumber);
        WebserviceHelper webserviceHelper = new WebserviceHelper(getActivity());
        String jsonConvertedString = makeJsonConvertedString();
        webserviceHelper.createOrder(jsonConvertedString, new WebserviceCompletionListener() {
            @Override
            public void onCompletedWithError(String errorDescription) {
                Log.e("test", "on erroe called");
                Dialogs.hideProgressDialog(layoutCardNumber);
                new MaterialDialog.Builder(getActivity())
                        .title(R.string.app_name)
                        .content(errorDescription)
                        .positiveText("OK")
                        .show();
            }

            @Override
            public void onCompletedWithData(iCannPayArrayList data) {

            }

            @Override
            public void onCompleted(iCannPayObject responseObj) {
                Dialogs.hideProgressDialog(layoutCardNumber);
                Log.e("test", "on erroe called");
                double amount = session.getUserCart().getAmount();
                session.testingAmount = amount;
                session.clearUserCart();
                UserCart userCart = new UserCart();
                userCart.setAmount(amount);
                userCart.setDescriptor(((OrderModel) responseObj).getDescription());
                session.setUserCart(userCart);
                session.descriptor = ((OrderModel) responseObj).getDescription();
                OrderModel orderModel = (OrderModel) responseObj;
                session.orderId = orderModel.getOrderId();
                session.getUserCart().setOrderModel(orderModel);
                ((HomeActivity) getActivity()).replaceFragment(new AdditionalInfo(), true);
            }
        });
    }

    private String makeJsonConvertedString() {
        AdditionalInfoModel additionalInfoModel = session.getUserCart().getAdditionalInfoModel();
        CardInformationModel cardInformationModel = session.getUserCart().getCardInformationModel();
        JSONObject mainObject = new JSONObject();
        try {
            JSONObject customerInfo = new JSONObject();
            if (additionalInfoModel != null) {
                customerInfo.put("email", additionalInfoModel.getEmail());
                customerInfo.put("address1", additionalInfoModel.getAddress());
                customerInfo.put("address2", additionalInfoModel.getAddress1());
                customerInfo.put("city", additionalInfoModel.getCity());
                customerInfo.put("state", additionalInfoModel.getState());
                customerInfo.put("zipcode", "12345");
                customerInfo.put("phone", additionalInfoModel.getTelephone());
            }
            mainObject.put("customer_info", customerInfo);
            JSONArray products = new JSONArray();
            mainObject.put("products", products);
            mainObject.put("numeric_pad_amount", String.valueOf(session.getUserCart().getAmount()));
            mainObject.put("total_amount", String.valueOf(session.getUserCart().getAmount()));
            mainObject.put("pay_by_cash_amount", "0");
            JSONObject creditCard = new JSONObject();
            creditCard.put("is_swipe", "0");
            creditCard.put("cc_name", cardInformationModel.getNameOnCard());
            creditCard.put("cc_number", cardInformationModel.getNumberOnCard());
            String date = cardInformationModel.getExpirationDate();
            String[] splitedDate = date.split("/");
            creditCard.put("cc_expiry_year", splitedDate[1]);
            creditCard.put("cc_expiry_month", splitedDate[0]);
            creditCard.put("cc_code", cardInformationModel.getCvv());
            mainObject.put("pay_by_credit_card", creditCard);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return mainObject.toString();
    }

    private void fillCardInformationModel() {
        cardInformationModel = new CardInformationModel();
        cardInformationModel.setNameOnCard(etNameOnCard.getText().toString());
        cardInformationModel.setNumberOnCard(etCardNumber.getText().toString());
        cardInformationModel.setCvv(Integer.parseInt(etCvv.getText().toString()));
        cardInformationModel.setExpirationDate(etExpiryDate.getText().toString());
    }

    public void showDatePickerDialog(IDatePickerListener _listener) {
        DatePickerFragment newFragment = new DatePickerFragment();
        newFragment.set_iDatePickerListener(_listener);
        newFragment.show(getActivity().getFragmentManager(), "datePicker");
        newFragment.setTolimit(true);
        newFragment.setToMinimum(true);
    }

    @Override
    public void onFocusChange(View view, boolean b) {

        if (b) {
            switch (view.getId()) {
                case R.id.et_name_on_card:
                    showKeyboard(etNameOnCard);
                    break;
                case R.id.et_card_number:
                    showKeyboard(etCardNumber);
                    break;
                case R.id.et_scc:
                    showKeyboard(etCvv);
                    break;
                case R.id.et_expiration_date:
                    hideKeyboard(etExpiryDate);
                    showDatePickerDialog(new IDatePickerListener() {
                        @Override
                        public void afterSetDate(int year, int month, int day) {
                            String s = String.format("%d/%d", month + 1, year);
                            etExpiryDate.setText(s);
                        }
                    });
                    break;
            }
        }

    }

    private void showKeyboard(EditText editText) {
        InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
    }

    private void hideKeyboard(TextView editText) {
        InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
    }

    private boolean validateAllFields() {
        if (TextUtils.isEmpty(etNameOnCard.getText().toString())) {
            Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.required_name));
            return false;
        }
        if (TextUtils.isEmpty(etCardNumber.getText().toString())) {
            Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.required_card));
            return false;
        } else {
            if (etCardNumber.getText().toString().length() < 16 || etCardNumber.getText().toString().length() > 19) {
                Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), "Enter valid credit card number");
                return false;
            }
        }
        if (TextUtils.isEmpty(etExpiryDate.getText().toString())) {
            Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.required_date));
            return false;
        }
        if (TextUtils.isEmpty(etCvv.getText().toString())) {
            Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.required_cvv));
            return false;
        } else {
            if (etCvv.getText().toString().length() > 4 || etCvv.getText().toString().length() < 3) {
                Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.error_cvv));
                return false;
            }
        }
        return true;
    }
}
public class SwipeCardFragment extends BaseFragment implements View.OnFocusChangeListener {

    private View view;
    private TextView tvTotal, tvTotalAmount, tvCardInfo;
    private TextView btnRecordPayment;
    private EditText etExpiryDate, etNameOnCard, etCardNumber, etCvv;
    private CardInformationModel cardInformationModel;
    private RelativeLayout layoutCardNumber;

    public SwipeCardFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_swipe_card, container, false);
        initViews();
        setClickListener();
        setCustomFonts();


        setValuesToUIFromSession();

        ((HomeActivity) getActivity()).visibilityOfCounter(false);
        ((HomeActivity) getActivity()).setVisibilityOfEditIcon(false);

        requestFocusToCVV();

        return view;
    }

    private void requestFocusToCVV() {
        etCvv.requestFocus();
    }

    private void setValuesToUIFromSession() {
        double amount = session.getUserCart().getAmount();
        String formattedAmount = String.format("%.2f", amount);
        tvTotalAmount.setText("$" + formattedAmount);
        CardInformationModel cardInformationModel = session.getUserCart().getCardInformationModel();
        if (cardInformationModel != null) {
            etNameOnCard.setText(cardInformationModel.getNameOnCard());
            etCardNumber.setText(String.valueOf(cardInformationModel.getNumberOnCard()));
            etExpiryDate.setText(cardInformationModel.getExpirationDate());
            //etCvv.setText(String.valueOf(cardInformationModel.getCvv()));
        }
    }

    private void setCustomFonts() {

        iCannPayUtils.setCustomFontToTextView(getActivity(), tvTotal, Constants.FUTURA_BOOK);
        iCannPayUtils.setCustomFontToTextView(getActivity(), tvTotalAmount, Constants.FUTURA_BOOK);
        iCannPayUtils.setCustomFontToTextView(getActivity(), tvCardInfo, Constants.FUTURA_BOOK_BOLD);

    }

    private void setClickListener() {
        btnRecordPayment.setOnClickListener(this);
        etExpiryDate.setOnFocusChangeListener(this);
    }

    private void initViews() {
        tvTotal = (TextView) view.findViewById(R.id.tv_total);
        tvTotalAmount = (TextView) view.findViewById(R.id.tv_total_amount);
        tvCardInfo = (TextView) view.findViewById(R.id.tv_sign_receipt);
        btnRecordPayment = (TextView) view.findViewById(R.id.btn_record_payment);
        etExpiryDate = (EditText) view.findViewById(R.id.et_expiration_date);
        etNameOnCard = (EditText) view.findViewById(R.id.et_name_on_card);
        etCardNumber = (EditText) view.findViewById(R.id.et_card_number);
        etCvv = (EditText) view.findViewById(R.id.et_scc);
        layoutCardNumber = (RelativeLayout) view.findViewById(R.id.layout_card_number);


    }

    @Override
    public String getName() {
        return "Record Card Swipe";
    }

    @Override
    public void onClick(View view) {

        switch (view.getId()) {
            case R.id.btn_record_payment:
                if (validateAllFields()) {
                    //((HomeActivity)getActivity()).replaceFragment(new AdditionalInfo(), true);
                    fillCardInformationModel();
                    session.getUserCart().setCardInformationModel(cardInformationModel);
                    createOrder();
                }
                break;
        }

    }

    private void createOrder() {
        Dialogs.showProgressDialog(getActivity(), layoutCardNumber);
        WebserviceHelper webserviceHelper = new WebserviceHelper(getActivity());
        String jsonConvertedString = makeJsonConvertedString();
        webserviceHelper.createOrder(jsonConvertedString, new WebserviceCompletionListener() {
            @Override
            public void onCompletedWithError(String errorDescription) {
                Dialogs.hideProgressDialog(layoutCardNumber);
                new MaterialDialog.Builder(getActivity())
                        .title(R.string.app_name)
                        .content(errorDescription)
                        .positiveText("OK")
                        .show();
            }

            @Override
            public void onCompletedWithData(iCannPayArrayList data) {

            }

            @Override
            public void onCompleted(iCannPayObject responseObj) {
                Dialogs.hideProgressDialog(layoutCardNumber);

                double amount = session.getUserCart().getAmount();

                session.testingAmount = amount;

                session.clearUserCart();

                UserCart userCart = new UserCart();
                userCart.setAmount(amount);

                session.setUserCart(userCart);
                session.descriptor = ((OrderModel) responseObj).getDescription();

                OrderModel orderModel = (OrderModel) responseObj;

                session.orderId = orderModel.getOrderId();

                session.getUserCart().setOrderModel(orderModel);

                ((HomeActivity) getActivity()).replaceFragment(new AdditionalInfo(), true);
            }


        });
    }

    private String makeJsonConvertedString() {

        AdditionalInfoModel additionalInfoModel = session.getUserCart().getAdditionalInfoModel();
        CardInformationModel cardInformationModel = session.getUserCart().getCardInformationModel();

        JSONObject mainObject = new JSONObject();

        try {
            JSONObject customerInfo = new JSONObject();

            if (additionalInfoModel != null) {

                customerInfo.put("email", additionalInfoModel.getEmail());
                customerInfo.put("address1", additionalInfoModel.getAddress());
                customerInfo.put("address2", additionalInfoModel.getAddress1());
                customerInfo.put("city", additionalInfoModel.getCity());
                customerInfo.put("state", additionalInfoModel.getState());
                customerInfo.put("zipcode", "12345");
                customerInfo.put("phone", additionalInfoModel.getTelephone());
            }

            mainObject.put("customer_info", customerInfo);

            JSONArray products = new JSONArray();

            mainObject.put("products", products);
            mainObject.put("numeric_pad_amount", String.valueOf(session.getUserCart().getAmount()));
            mainObject.put("total_amount", String.valueOf(session.getUserCart().getAmount()));
            mainObject.put("pay_by_cash_amount", "0");

            JSONObject creditCard = new JSONObject();

            creditCard.put("is_swipe", "1");
            creditCard.put("cc_name", cardInformationModel.getNameOnCard());
            creditCard.put("cc_number", cardInformationModel.getNumberOnCard());
            creditCard.put("cc_expiry_year", "2016");
            creditCard.put("cc_expiry_month", "12");
            creditCard.put("cc_code", cardInformationModel.getCvv());

            mainObject.put("pay_by_credit_card", creditCard);


        } catch (JSONException e) {
            e.printStackTrace();
        }
        return mainObject.toString();
    }

    private void fillCardInformationModel() {
        cardInformationModel = new CardInformationModel();

        cardInformationModel.setNameOnCard(etNameOnCard.getText().toString());
        cardInformationModel.setNumberOnCard(etCardNumber.getText().toString());
        cardInformationModel.setCvv(Integer.parseInt(etCvv.getText().toString()));
        cardInformationModel.setExpirationDate(etExpiryDate.getText().toString());
    }

    public void showDatePickerDialog(IDatePickerListener _listener) {
        DatePickerFragment newFragment = new DatePickerFragment();
        newFragment.set_iDatePickerListener(_listener);
        newFragment.show(getActivity().getFragmentManager(), "datePicker");
        newFragment.setTolimit(true);
        newFragment.setToMinimum(true);
    }

    @Override
    public void onFocusChange(View view, boolean b) {

        if (b) {
            showDatePickerDialog(new IDatePickerListener() {
                @Override
                public void afterSetDate(int year, int month, int day) {
                    String s = String.format("%d/%d", month + 1, year);
                    etExpiryDate.setText(s);
                    etExpiryDate.setFocusable(false);
                }
            });
        }

    }

    private boolean validateAllFields() {

        if (TextUtils.isEmpty(etNameOnCard.getText().toString())) {
            Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.required_name));
            return false;
        }

        if (TextUtils.isEmpty(etCardNumber.getText().toString())) {
            Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.required_card));
            return false;
        } else {
            //card # is not empty but validate for valid card number

            if (etCardNumber.getText().toString().length() < 16) {
                Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), "Enter valid credit card number");
                return false;
            }
          /*  if (!SecurityHelper.isMasterCardValid(etCardNumber.getText().toString())) {
                Dialogs.showAlertDialog(getActivity(), getString(R.string.error_credit_card));
                return false;
            }*/

        }

        if (TextUtils.isEmpty(etExpiryDate.getText().toString())) {
            Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.required_date));
            return false;
        }

        if (TextUtils.isEmpty(etCvv.getText().toString())) {
            Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.required_cvv));
            return false;
        } else {
            //Cvv code is not empty but validate for length
            if (etCvv.getText().toString().length() > 4 || etCvv.getText().toString().length() < 3) {
                Dialogs.showAlertDialogValidation(getActivity(), getString(R.string.invalid_info), getString(R.string.error_cvv));
                return false;
            }


        }

        return true;
    }
}
\$\endgroup\$
  • \$\begingroup\$ I've edited your post into shape. If possible, consider including the BaseFragment base class. \$\endgroup\$ – Mathieu Guindon Jul 4 '16 at 20:06
  • \$\begingroup\$ I already have a base class that is loading these fragments.The architecture is like this. I have a base class extending from Activity and then my every class is inheriting from base class.In this current case, I have a class named FragmentActivity that is inheriting from base class and this FragmentActivity class contains above mentioned fragments.Any help or any suggestions now? \$\endgroup\$ – Abdul Waheed Jul 4 '16 at 23:57
3
\$\begingroup\$

Your friend is suggesting you have a class that does the common work, and then subclasses to handle specialized work. This is really core OOP.

For example, your base class (say, CardTransactionFragment) might have an onCreateView method like this:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,                            Bundle savedInstanceState) {
        view = inflater.inflate(mLayoutId, container, false);
        initViews();
        setClickListener();
        setCustomFonts();
        setValuesToUIFromSession();
        ...

Then when you create the subclass, you'd set mLayoutId somehow (either directly through a setter, or with Intent arguments, or most likely have that class be abstract and define mLayoutId in the subclass).

Then in each subclass, you'd call super.onCreateView, as well as any other specific functionality, in the subclass's definition of onCreateView.

That's just an example, and could be handled differently. Generally speaking, if you see the same block of code in multiple places, you could probably optimize that away.

Single Responsibility Principle is not relevant in any way here. Basic inheritance (https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)) and DRY (https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) are much more appropriate to what you're describing.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.