Strategy design pattern Example? - java

Following is stretagy design pattern example take from here.
First of all we will create the interface for our strategy, in our case to pay the amount passed as argument.
public interface PaymentStrategy {
public void pay(int amount);
}
public class CreditCardStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate){
this.name=nm;
this.cardNumber=ccNum;
this.cvv=cvv;
this.dateOfExpiry=expiryDate;
}
#Override
public void pay(int amount) {
System.out.println(amount +" paid with credit/debit card");
}
}
public class PaypalStrategy implements PaymentStrategy {
private String emailId;
private String password;
public PaypalStrategy(String email, String pwd){
this.emailId=email;
this.password=pwd;
}
#Override
public void pay(int amount) {
System.out.println(amount + " paid using Paypal.");
}
}
public class Item {
private String upcCode;
private int price;
public Item(String upc, int cost){
this.upcCode=upc;
this.price=cost;
}
public String getUpcCode() {
return upcCode;
}
public int getPrice() {
return price;
}
}
public class ShoppingCart {
//List of items
List<Item> items;
public ShoppingCart(){
this.items=new ArrayList<Item>();
}
public void addItem(Item item){
this.items.add(item);
}
public void removeItem(Item item){
this.items.remove(item);
}
public int calculateTotal(){
int sum = 0;
for(Item item : items){
sum += item.getPrice();
}
return sum;
}
public void pay(PaymentStrategy paymentMethod){
int amount = calculateTotal();
paymentMethod.pay(amount);
}
}
public class ShoppingCartTest {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
Item item1 = new Item("1234",10);
Item item2 = new Item("5678",40);
cart.addItem(item1);
cart.addItem(item2);
//pay by paypal
cart.pay(new PaypalStrategy("myemail#example.com", "mypwd"));
//pay by credit card
cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
}
}
I want to ask what is use of strategy pattern here?Once we have created a strategy in main.We have access to Strategy class now.We can directly call pay() method from there?Why do we need interface , all which does is call a method?

1. I want to ask what is use of strategy pattern here?
The answer is the user who has the ShoppingCart (ShoppingCart cart = new ShoppingCart();)
2. We can directly call pay() method from there?
I don't know exactly you mean
3. Why do we need interface , all which does is call a method?
We need the interface PaymentStrategy because we need use Polymorphism to implement many way to pay (paypal or credit card), let's change the source a bit and you can see clearer:
public class ShoppingCart {
// other functions
public void pay(PaymentStrategy paymentMethod, int amount){
paymentMethod.pay(amount);
}
public void payWithStrategy() {
int amount = calculateTotal();
if (amount > 10000) { // because your credit card limit is 10000$ so you must use paypal
pay(new PaypalStrategy("myemail#example.com", "mypwd"), amount);
}
else { // you really like credit card so when the money lower than the card limit, you always choose it
pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"), amount);
}
}
}
public class ShoppingCartTest {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
Item item1 = new Item("1234",10);
Item item2 = new Item("5678",40);
cart.addItem(item1);
cart.addItem(item2);
cart.payWithStrategy();
}
}

Related

Printing specific data from an array, fulfilling conditions

I have been tasked with writing a code to create 4 classes(Main, Person,Account,Vehicle)and create objects of the Person class as per user requirements, doing so using an array. I had to store data within the array via user input, and retrieve them as per user choice. Which I believe I have successfully done so. One of the two inputs I had to ask from the user were, "Do you have an Account" and "Do you have a vehicle". If the User answers "Yes", I had to pass the object or something as a reference to the Account and Vehicle class to seclude them separately as well, and when the User asks for the People with an Account and Vehicle, It were to print the details of those specific users only.
.
Here is my code below
Main.java:
package com.company;
import java.util.Scanner;
public class Main {
public static int ids;
static int choice = 0;
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
menus();
}
public static void conditions(int choice){
switch (choice) {
case 1:
int i;
System.out.println("Enter id of person");
i = sc.nextInt();
Person user2[] = new Person[10];
user2[i] = new Person();
user2[i].setArray(i,user2);
//Getters
int k;
System.out.println("Enter id of existing person to retrieve info or press 0 to go to menu");
int l;
l = sc.nextInt();
if (l == 0) {
menus();
}
else {
System.out.println(user2[l].getName());
System.out.println(user2[l].getGender());
System.out.println(user2[l].getAge());
System.out.println(user2[l].isAccount());
System.out.println(user2[l].isVehicle());
}
case 2:
//Call getters
Account a1=new Account();
a1.getArrays();
case 3:
Vehicle v1=new Vehicle();
v1.printArray();
}
}
public static void menus() {
System.out.println("Choose an option");
System.out.println("1.Enter new person details");
System.out.println("2.Does not work(should display people who want an acc only");
System.out.println("3.Does not work(Should display people who have a vehicle only)");
choice = sc.nextInt();
conditions(choice);
}
}
Person.java:
package com.company;
import java.util.Scanner;
public class Person {
private String name;
private int age;
private String gender;
private static String Account;
private static String Vehicle;
Person array[];
public String isAccount() {
return Account;
}
public void setAccount(String account) {
Account = account;
}
public String isVehicle() {
return Vehicle;
}
public void setVehicle(String vehicle) {
Vehicle = vehicle;
}
public Person[] getArray() {
return array;
}
public void setArray(int i,Person[] array) {
this.array = array;
Scanner sc=new Scanner(System.in);
System.out.println("Enter name");
name=sc.next();
array[i].setName(name);
System.out.println("Enter age");
age=sc.nextInt();
array[i].setAge(age);
System.out.println("Enter gender");
gender=sc.next();
array[i].setGender(gender);
System.out.println("Enter Yes if you want an account,No if otherwise");
Account=sc.next();
if(Account=="Yes"){
Account user3[] = new Account[10];
user3[i].setArray(i,this.array);
user3[i] = new Account(i,name,gender,Account);
}
else{
array[i].setAccount("No");
}
System.out.println("Enter Yes if you have a vehicle, No if otherwise");
Vehicle=sc.next();
if(Vehicle=="Yes"){
Vehicle user4[] = new Vehicle[10];
user4[i] = new Vehicle();
user4[i].setArray(i,this.array);
}
else{
array[i].setVehicle("No");
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
Accounts.java:
package com.company;
public class Account extends Person{
Account[] arrays;
private int ages;
private String names;
private String genders;
private String vehicles;
private String accounts;
Account(int id,String names,String genders,String accounts){
arrays[id].setNames(names);
arrays[id].setAges(ages);
arrays[id].setGenders(genders);
arrays[id].setAccounts(accounts);
}
Account(){
}
public com.company.Account[] getArrays() {
return arrays;
}
public void setArrays(com.company.Account[] arrays) {
this.arrays = arrays;
}
public int getAges() {
return ages;
}
public void setAges(int ages) {
this.ages = ages;
}
public String getNames() {
return names;
}
public void setNames(String names) {
this.names = names;
}
public String getGenders() {
return genders;
}
public void setGenders(String genders) {
this.genders = genders;
}
public String getVehicles() {
return vehicles;
}
public void setVehicles(String vehicle) {
this.vehicles = vehicles;
}
public String getAccounts() {
return accounts;
}
public void setAccounts(String accounts) {
this.accounts = accounts;
}
public void printArray(){
for(int k=0;k<array.length;k++){
System.out.println(array[k]);
}
}
}
My Vehicle class is the same as Accounts.
-To seclude and print
-I have tried to pass the array from the Person class to the Accounts class and Vehicle, If the User does wish to have an Account and has a Vehicle.
-However, upon printing via for loop or a basic getter, I am met with an Error "this.array is null" which probably means my Array isnt being passed or stored within the Account class.
-Maybe there is a simpler way of secluding and printing them, as per the task I have to implement the use of Abstraction, Arrays, Constructors and Functions.
I am new to Java and the Stackoverflow platform, so please forgive me If the formatting of the question isnt precise. Hope to recieve some detailed help on getting around this.

Add Part object to observableArrayList<Part> associatedParts in the Product class in Java

I am working on my class assignment and I am stuck.
I have two classes: Part, which is abstract and has InHouse and Outsourced classes that extend Part. Then I have Product, which oddly has an observableArrayList of parts called associatedParts.
I am working on my AddProductController, trying to make a call to the method in the Product class addAssociatedPart(). My problem is the compiler doesn't find the method in Part. If I cast to an InHouse, it doesn't find the method in InHouse, and so on. I can't use a static method, because the method addAssociatedPart() is supposed to be non-static per the UML design. So, I can't tell it explicitly to find it in Product.addAssociatedPart(), because it tells me I can't reference a non-static etc.
Here's the code snippets starting with the Product class.
public class Product {
private ObservableList<Part> associatedParts = FXCollections.observableArrayList();
private int id;
private String name;
private double price;
private int stock;
private int min;
private int max;
public void addAssociatedPart(Part part) {
getAllAssociatedParts().add(part);
}
public ObservableList<Part> getAllAssociatedParts() {
return this.associatedParts;
}
And then the AddProductScreenController class:
public class AddProductScreenController implements Initializable {
#FXML
public void onAddProductAddPart(ActionEvent event) {
// this is triggered when the Add button is clicked
Part selectedItem = addProductTableViewAll.getSelectionModel().getSelectedItem();
selectedItem.addAssociatedPart(); // can't find method
Product.selectedItem.addAssociatedPart(); // can't find variable selectedItem (obviously bad formatting)
selectedItem.Product.addAssociatedPart(); // can't find variable Product (again bad formatting)
addAssociatedPart(selectedItem); // can't find method addAssociatedPart()
Product.addAssociatedPart(selectedItem); // non-static method, can't be referenced from a static context
InHouse newPart = new InHouse(1, "test", 1.99, 1, 1, 1, 101);
addAssociatedPart(newPart); // can't find method
Product.addAssociatedPart(newPart); // non-static method
newPart.addAssociatedPart(); // can't find method
addProductTableViewPartial.setItems(associatedParts);
}
}
The part code as requested:
public abstract class Part {
private int id;
private String name;
private double price;
private int stock;
private int min;
private int max;
public ObservableList<Part> allParts = FXCollections.observableArrayList();
public Part(int id, String name, double price, int stock, int min, int max) {
this.id = id;
this.name = name;
this.price = price;
this.stock = stock;
this.min = min;
this.max = max;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setPrice(double price) {
this.price = price;
}
public double getPrice() {
return this.price;
}
public void setStock(int stock) {
this.stock = stock;
}
public int getStock() {
return this.stock;
}
public void setMin(int min) {
this.min = min;
}
public int getMin() {
return this.min;
}
public void setMax(int max) {
this.max = max;
}
public int getMax() {
return this.max;
}
}
This is InHouse
package model;
public class InHouse extends Part {
private int machineId;
public InHouse(int id, String name, double price, int stock, int min, int max, int machineId) {
super(id, name, price, stock, min, max);
this.machineId = machineId;
}
public void setMachineId(int machineId) {
this.machineId = machineId;
}
public int getMachineId() {
return this.machineId;
}
}
And then Outsourced:
package model;
public class Outsourced extends Part {
private String companyName;
public Outsourced(int id, String name, double price, int stock, int min, int max, String companyName) {
super(id, name, price, stock, min, max);
this.companyName = companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getCompanyName() {
return this.companyName;
}
}
If there is a particular part of Java you feel I need to brush up on to understand this, I am wide open to that. I want to understand the issue, not just get a fix. I'm not even looking for the answer, just a point in the direction of what the problem is.
Update
#Le and #Jackson pointed me in the right direction with their comments on the response he provided. I need to have a product first:
Product product = new Product(1, "test", 1.99, 1, 1, 1);
product.addAssociatedPart(selectedItem);
I was trying to explain you association of your various classes in comments but thought I would use visual help. I have simplified your scenario into a classic OOP problem.
public class Product {
public void addAssociatedPart(Part part) {
// some stuff
}
}
public abstract class Part {
}
public class InHouse extends Part {
}
public class Outsourced extends Part {
}
public class Assembly {
public static void main(String[] args) {
Product car = new Product();
Part seat = new InHouse();
Part engine = new Outsourced();
Part window = new InHouse();
car.addAssociatedPart(seat);
car.addAssociatedPart(engine);
car.addAssociatedPart(window);
}
}
I do not have any method in my Part or its sub-classes to add themselves to some Product. Was this you trying to achieve?
I am working on my AddProductController, trying to make a call to the
method in the Product class addAssociatedPart().
My problem is the compiler doesn't find the method in Part.
Why should it? Is Part a child of Product? Otherwise, you are calling a Product Method using a Part instance.
To use the methods of Inhouse and Oursourced for parts, you can do something like this
if (selectedItem instanceof InHouse){
Inhouse inhouse = (Inhouse)selectedItem;
//do what you need with inhouse methods
}else{
Outsourced outsourced = (Outsourced)selectedItem;
//do what you need with oursourced method
}
You are confused with static and non static method. You need a Product instance to access AddAssociatedPart(). Visualize your class in class diagram.
public void onAddProductAddPart(ActionEvent event) {
// this is triggered when the Add button is clicked
Part selectedItem = addProductTableViewAll.getSelectionModel().getSelectedItem();
selectedItem.addAssociatedPart(); // addAssociatedPart() is method of Product, not Part
Product.selectedItem.addAssociatedPart(); // Product class has no static member selectedItem
selectedItem.Product.addAssociatedPart(); // syntax error
addAssociatedPart(selectedItem); // addAssociatedPart() is not method of AddProcutController
Product.addAssociatedPart(selectedItem); // if you reference the method start with a class, the method is expected to be a static method. addAssociatedPart() is not a static method, call it with a product instance
InHouse newPart = new InHouse(1, "test", 1.99, 1, 1, 1, 101);
addAssociatedPart(newPart); // addAssociatedPart() is not part of AddProductController
Product.addAssociatedPart(newPart); // dont reference non-static method with a class name
newPart.addAssociatedPart(); // addAssociatedPart() is not part of Part
addProductTableViewPartial.setItems(associatedParts);
}

Calling getName() method in one class work but in another it does not

I am making a program to iterate through an arraylist of objects and print them to the screen. To do this I am using a getName() method. When I call it from one of my classes, nothing is returned, but calling it from a different class works.
public class Customer {
String name;
public Customer(String name) {
this.name=name;
}
public String getName() {
return this.name;
}
}
The code above is the getName() method I want to call.
public class Store {
private String name;
private ArrayList<Customer> customersStore;
public Store(String name) {
this.name=name;
customersStore=new ArrayList<Customer>();
}
public void addCustomer(Customer customer) {
customersStore.add(customer);
for(int i = 0; i<customersStore.size();i++){
System.out.print(customersStore.get(i).getName() + " ");
}
}
public String getName() {
return this.name;
}
public ArrayList<Customer> getCustomers() {
return this.customersStore;
}
}
Because the program was not printing anything off as a way of debugging I had the program print off the arraylist whenever a new value was entered and found that it worked.
public class StoreView implements Observer{
public void printStoreDetails(Store store) {
ArrayList<Customer> customerList;
// Displaying the customer list
customerList = store.getCustomers();
// Displaying the values after iterating through the list
System.out.println("\nThe Customer names are:");
for(int i = 0; i<customerList.size();i++){
System.out.print(customerList.get(i).getName() + " ");
}
}
#Override
public void update(Observable o, Object name) {
printStoreDetails(new Store("Sears"));
}
}
However, when I try to call it from the StoreView class above, it does not print anything off. Which is what I dont understand.
The input is gathered from a scanner in the main class
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Store myStore = new Store("Sears");
StoreView myStoreView = new StoreView();
StoreController myStoreController = new StoreController(myStore, myStoreView);
Customer aCustomer;
System.out.println("Enter customer names for store " + myStore.getName());
myStoreController.addObserver(myStoreView);
while(input.hasNext()) {
aCustomer = new Customer(input.nextLine());
myStoreController.addCustomer(aCustomer);
}
}
}
The input is then sent to StoreController to be added to the ArrayList
public class StoreController extends Observable {
private Store model;
private StoreView view;
public StoreController(Store model, StoreView view){
this.model = model;
this.view = view;
}
public void addCustomer(Customer name){
model.addCustomer(name);
setChanged();
notifyObservers();
}
}
I'm not super familiar with observers but the overall goal of the program is to update StoreView whenever customers are added to the Store through StoreController. Any help is appreciated.
You are creating a new instance of Store when updating the observer; thus, it has an empty array of customers.
Change notifyObservers(); to notifyObservers(model); and the update method to:
#Override
public void update(Observable o, Object store) {
if (store instanceof Store) {
printStoreDetails((Store) store);
}
}

Writing a static method for the following code

I need to write up a static method that takes an array of Vehicles and print each registration number in the array. The object in the array is either a Vehicle, a Car, or a Truck object reference. Finally, I need to print the registration number of the object on a single line on its own.
So the code is:
public class Vehicle {
private String registrationNumber;
public Vehicle(String rego) {
registrationNumber = rego;
}
public String getRegistrationNumber() {
return registrationNumber;
}
}
public class Car extends Vehicle {
int passengers;
public Car(String rego, int pass) {
super(rego);
passengers = pass;
}
public int getPassengers() {
return passengers;
}
}
public class Truck extends Vehicle {
int tons;
public Truck(String rego, int tons) {
super(rego);
this.tons = tons;
}
public int getTons() {
return tons;
}
}
I have to write up a static method for the following test and get the following, but I am having some trouble.
Test and expected Result
This is what I have done so far:
public static void printRegNum(Vehicle[] list){
for (int i = 0; i < list.length; i++){
System.out.println(list[i]);
}
}
The 1st way to play with your System.out.println(list[i]); is to override the toString() method in class Vehicle:
public class Vehicle {
private String registrationNumber;
public Vehicle(String rego) {
registrationNumber = rego;
}
public String getRegistrationNumber() {
return registrationNumber;
}
public String toString() {
return registrationNumber;
}
}
The 2nd way is change:
from:
System.out.println(list[i]);
to:
System.out.println(list[i].getRegistrationNumber());
Hope those can help.
Not getting where's the problem
i.e.
public static void main(String[] args){
Car car = new Car("MYCAR",4);
Truck t = new Truck("MYTRUCK", 16);
Vehicle[] myList = new Vehicle[] {car, t};
printRegNum(myList);
}
Also seems that you only need to print the "rego".
System.out.println(list[i].getRegistrationNumber());

Reduse integer everytime an new object is added to arraylist

I have a class of Person with an ArrayList of the class Groceries.
Let's name the Arraylist shoppingBag.
Student and Groceries has one field each, int money and int price.
The specific amount of money and price is up to you when initializing new objects.
So every time a Person adds an object of Groceries to his shoppingBag, the amount of money he has needs to be reduced with the total price of groceries added to the bag.
How do you do that?
So, let my try to understand what you want (as I do the same for my clients)
You have a class Groceries with price field:
class Groceries {
private int price;
public Groceries(int price) {
this.price = price;
}
public int getPrice() {
return price;
}
#Override
public String toString() {
return "Groceries{" +
"price=" + price +
'}';
}
}
And class person with int money filed and shopping bag field as List of Groceries:
class Person {
private List<Groceries> shoppingBag = new ArrayList<>();
private int money;
public Person(int money) {
this.money = money;
}
public List<Groceries> getShoppingBag() {
return shoppingBag;
}
public int getMoney() {
return money;
}
}
Firstly you create an instance of Person with some mount of money: Person person = new Person(150);
And then each time when you add a groceries to the shopping bag, like person.getShoppingBag().add(new Groceries(10)); you do want to reduce amount of money from the person instance.
So, If I am correct, you need to implement several things:
1) You should forbid adding groceries to the shopping bag with the way described before. We need to throw an exception when someone tries to add an element to the List via getter. It can be implemented using an Unmodifiable copy of your list:
public List<Groceries> getShoppingBag() {
List<Groceries> bag = new UnmodifiableArrayList<>(shoppingBag.toArray(new Groceries[shoppingBag.size()]), shoppingBag.size());
return bag;
}
or a little bit nicely and shortly using Guava:
public List<Groceries> getShoppingBag() {
List<Groceries> bag = ImmutableList.copyOf(shoppingBag);
return bag;
}
2) Add a method that will add a groceries directly. You can also throw an exception if there is no enough money to not have negative balance:
public void addToShoppingBag(Groceries groceries) {
if (0 > money - groceries.getPrice()) {
throw new IllegalStateException("You have not enough money!");
}
shoppingBag.add(groceries);
money -= groceries.getPrice();
}
3) Probably you will need to have possibility to add some money:
private void addMoney(int amout) {
money += amout;
}
Please see the completely demo example:
class Demo {
public static void main(String[] args) throws IOException {
Person person = new Person(42);
try {
System.out.println(person.getMoney());
person.addToShoppingBag(new Groceries(12));
person.addToShoppingBag(new Groceries(20));
person.addToShoppingBag(new Groceries(5));
System.out.println(person.getMoney());
System.out.println(person.getShoppingBag());
person.getShoppingBag().add(new Groceries(1));
} catch (UnsupportedOperationException e) {
e.printStackTrace();
}
try {
person.addToShoppingBag(new Groceries(66));
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
class Person {
private List<Groceries> shoppingBag = new ArrayList<>();
private int money;
public Person(int money) {
this.money = money;
}
public List<Groceries> getShoppingBag() {
List<Groceries> bag = ImmutableList.copyOf(shoppingBag);
return bag;
}
public void addToShoppingBag(Groceries groceries) {
if (0 > money - groceries.getPrice()) {
throw new IllegalStateException("You have not enough money!");
}
shoppingBag.add(groceries);
money -= groceries.getPrice();
}
private void addMoney(int amout) {
money += amout;
}
public int getMoney() {
return money;
}
}
class Groceries {
private int price;
public Groceries(int price) {
this.price = price;
}
public int getPrice() {
return price;
}
#Override
public String toString() {
return "Groceries{" +
"price=" + price +
'}';
}
}
PS: Please next time describe some examples of code and demos to get an answer :)

Categories