I have an instance of class Address, which I have to change according to environment:
1) Region: base class with sub-classes RegionA and RegionB
2) Site: base class with sub-classes SiteA, SiteB and SiteC
3) Language: base class with sub-classes LanguageA and LanguageB
Each subclass defines constraints about Address modification.
The problem is that each tuple (Region, Site, Language) has to define its own modifier.
So, I have a method adjust(Address a, Region r, Site s, Language l):
void adjust(Address a, Region r, Site s, Language l){
if(r instanceof Russia && s instanceof MailRu && Language instanceof Russian){
a.set_street("abc")
}
else if(r instanceof Russia && s instanceof MailRu && Language instanceof English){
a.set_street("fgh")
}
}
What is the best design patter to use in this case?
Use polymorphism to loose the ifs and instanceofs!
Use the abstract factory pattern for easier creation of the street info.
Region and Language are the (sub)products (resp. their factories, when you consider the way I did it), which are used to create the street in Address.
package address.example;
public class AddressExample
{
public static void main(String[] args)
{
LanguageFactoryProvider lfp = new LanguageFactoryProvider.LanguageFactoryProviderImpl();
RegionFactoryProvider rfp = new RegionFactoryProvider.RegionFactoryProviderImpl();
AddressProvider provider = new AddressProvider(lfp, rfp);
Address a = provider.createAddress("RU", "USA", "Famous Street");
System.out.println(a.getStreet());
System.out.println("-----");
Address b = provider.createAddress("EN", "RUS", "Good Street");
System.out.println(b.getStreet());
}
}
Output is
Address format: RU
Famous Street
USA
-----
Address format: EN
Good Street
RUS
This is the Address class, as you can see it delegates parts of the street creation to region and language (it's nothing fancy, but you get the point).
package address.example;
import address.example.LanguageFactoryProvider.Language;
import address.example.RegionFactoryProvider.Region;
public interface Address
{
public String getStreet();
static class AddressImpl implements Address
{
private final Region region;
private final Language language;
private final String street;
public AddressImpl(Region region, Language language, String street)
{
this.region = region;
this.language = language;
this.street = street;
}
#Override
public String getStreet()
{
StringBuilder sb = new StringBuilder();
sb.append(String.format("Address format: %s", language.getSpecifier()));
sb.append(String.format("%n"));
sb.append(street);
sb.append(String.format("%n"));
sb.append(region.getSpecifier());
return sb.toString();
}
}
}
And here are the other used classes. I'll add some more thoughts to it another time.
package address.example;
import address.example.LanguageFactoryProvider.Language;
import address.example.RegionFactoryProvider.Region;
public class AddressProvider
{
private final LanguageFactoryProvider lfp;
private final RegionFactoryProvider rfp;
public AddressProvider(LanguageFactoryProvider lfp, RegionFactoryProvider rfp)
{
this.lfp = lfp;
this.rfp = rfp;
}
public Address createAddress(String language, String region, String street)
{
Language _language = lfp.getLanguageFactory(language).createLanguage();
Region _region = rfp.getRegionFactory(region).createRegion();
return new Address.AddressImpl(_region, _language, street);
}
}
package address.example;
import java.util.HashMap;
import java.util.Map;
public interface LanguageFactoryProvider
{
public LanguageFactory getLanguageFactory(String language);
static interface LanguageFactory
{
public Language createLanguage();
}
static interface Language
{
public String getSpecifier();
}
static class LanguageImpl implements Language
{
private final String specifier;
public LanguageImpl(String specifier)
{
this.specifier = specifier;
}
#Override
public String getSpecifier()
{
return specifier;
}
}
static class LanguageFactoryProviderImpl implements LanguageFactoryProvider
{
private static final Map<String, LanguageFactory> factories = new HashMap<>();
static
{
factories.put("EN", new EnglishLanguageFactory());
factories.put("RU", new RussianLanguageFactory());
}
#Override
public LanguageFactory getLanguageFactory(String language)
{
if (!factories.containsKey(language))
throw new IllegalArgumentException();
LanguageFactory factory = factories.get(language);
return factory;
}
}
static class RussianLanguageFactory implements LanguageFactory
{
#Override
public Language createLanguage()
{
return new LanguageImpl("RU");
}
}
static class EnglishLanguageFactory implements LanguageFactory
{
#Override
public Language createLanguage()
{
return new LanguageImpl("EN");
}
}
}
package address.example;
import java.util.HashMap;
import java.util.Map;
public interface RegionFactoryProvider
{
public RegionFactory getRegionFactory(String region);
static interface RegionFactory
{
public Region createRegion();
}
static interface Region
{
public String getSpecifier();
}
static class RegionImpl implements Region
{
private final String specifier;
public RegionImpl(String specifier)
{
this.specifier = specifier;
}
#Override
public String getSpecifier()
{
return specifier;
}
}
static class RegionFactoryProviderImpl implements RegionFactoryProvider
{
private static final Map<String, RegionFactory> factories = new HashMap<>();
static
{
factories.put("RUS", new RussianRegionFactory());
factories.put("USA", new UsRegionFactory());
}
#Override
public RegionFactory getRegionFactory(String region)
{
if (!factories.containsKey(region))
throw new IllegalArgumentException();
RegionFactory factory = factories.get(region);
return factory;
}
}
static class RussianRegionFactory implements RegionFactory
{
#Override
public Region createRegion()
{
return new RegionImpl("RUS");
}
}
static class UsRegionFactory implements RegionFactory
{
#Override
public Region createRegion()
{
return new RegionImpl("USA");
}
}
}
This is typical business "logic" with many cases/rules. It pays to make a declarative solution for this.
<rule>
<when category="Region" value="Russia"/>
<when category="Site" value="MailRu"/>
<action category="Address" value="abc"/>
</rule>
This allows to build in diagnostics, integrity checks, log uncovered cases, make historical logs for future analysis on future bug reports.
It might even be more readable. Transformable in a nice HTML table hierarchy for manager level documentation.
It boils down to the fact that your code is procedural, without possibility to store the control-flow path taken. A model-driven approach can alleviate that. A DSL would be feasible, but I find a free form data approach to be a bit more creative, direct.
Related
I hope you're doing well, I have a doubt when I try to create a method that can validate some business rules.
In this case, I have a class
public class ValidationUtils {
final List<CreditValidations> creditValidations;
public ValidationUtils(){
creditValidations = Arrays.asList(
new ValidateAge(),
new ValidateSalary()
);
}
public ValidationRs passAllValidations(Client client){
final var validationsFailed = new ArrayList<String>();
boolean validationResult = false;
for (CreditValidations creditValidationClasses : creditValidations){
validationResult = Boolean.logicalXor(creditValidationClasses .validate(client,validationsFailed),
validationResult);
}
final var rs = new ValidationRs();
rs.setSuccessfulValidations(validationResult);
rs.setValidationsFailed(validationsFailed);
return rs;
}
}
this class has a method called "passAllValidations" That method can evaluate each CreditValidation implementation and join their results, Using this code I don't need to create more methods when I have a new validation, only extends the abstraction and create the new Validation class and inject it in the ValidationUtils constructor.
the abstraction and implementation of CreditValidations look like
public abstract class CreditValidations {
protected final String errorCode;
protected CreditValidations(final String errorCode) {
this.errorCode = errorCode;
}
protected abstract boolean validate(final Client client,final List<String> validationsFailed);
protected boolean evaluateValidation(boolean validationResult, List<String> validationsFailed){
if (!validationResult){
setCode(validationsFailed);
}
return validationResult;
}
protected String getErrorCode() {
return this.errorCode;
}
protected void setCode(List<String> failedValidations) {
failedValidations.add(errorCode);
}
}
public class ValidateAge extends CreditValidations {
public ValidateAge() {
super(CreditValidationErrorEnum.ERROR_VALIDATING_AGE.getCode());
}
#Override
public boolean validate(final Client client, List<String> validationsFailed) {
return this.evaluateValidation(client.getAge() >= 18,validationsFailed);
}
}
in summary, my question is referring to the dependency injection in the class ValidationUtils, I don't know if it way is correct or if Spring Framework has some things that help me to inject all of the CreditValidation implementations and avoid using Array.asList(new NewValidationClass()) or another design pattern which can help.
Thanks in advance.
I would like to create an abstract factory. here is what I tried.
//abstract class Worker
public abstract class Worker {
String phoneNumber;
String firstName;
String lastName;
String workerType;
String ifu;
String imageParth;
//....
public String getWorkerType() {
return workerType;
}
}
// Electrician class which extends worker
package worker.domain.worker;
public class Electrician extends Worker{
public Electrician() {}
public Electrician(String phoneNumber, String firstName, String lastName, String ifu, String workerType,
String imageParth) {
super(phoneNumber, firstName, lastName, ifu,workerType, imageParth);
}
public String getWorkerType() {
return "Electrician";
}
}
//Mason class
package worker.domaine.worker;
public class Mason extends Worker{
public Mason() {};
public Mason(String phoneNumber, String firstName, String lastName, String ifu,String workerType,
String imageParth) {
super(phoneNumber, firstName, lastName, ifu, workerType, imageParth);
}
String getworkerType() {
return "Mason";
}
}
// interface WorkerAbstractFactory
package worker.domaine.worker;
public interface WorkerAbstractFactory {
Worker createWorker(String typeWorker);
}
//
public class WorkerFactory implements WorkerAbstractFactory{
#Override
public Worker createWorker(String typeWorker) {
Worker worker = null;
if(worker != null) {
switch (typeWorker) {
case "Electrician":
Electrician electrician =new Electrician();
electrician = new Electrician (electrician.getPhoneNumber(), electrician.getFirstName(), electrician.getLastName(), electrician.getIfu(), electrician.getWorkerType(),electrician.getImageParth());
case "Mason":
Mason mason =new Mason();
mason = new Mason (mason.getPhoneNumber(), mason.getFirstName(), mason.getLastName(), mason.getIfu(), mason.getworkerType(),mason.getImageParth());
}}
//app class
public class WorkerFactoryProvider {
public static WorkerAbstractFactory getWorkerFactory(String workerCategory) {
//WorkerFactory workerFactory = new WorkerFactory();
WorkerFactory workerFactory = new WorkerFactory();
if (workerCategory != null) {
switch (workerCategory) {
case "Electrician":
Worker worker1 = workerFactory.createWorker("Electrician");
worker1.getWorkerType();
String a=worker1.getWorkerType();
System.out.println(a);
case "Mason":
Worker worker2 = workerFactory.createWorker("Mason");
worker2.getWorkerType();
String b=worker2.getWorkerType();
System.out.println(b);
}
}
return null;
}
do you think it could work like that? now, if I really want a concrete object, how could it be done? because I would like to write for example a method to calculate the pay of each worker according to type for example how could I use my abstract Factory in the method to return me each type.
You have a single class hierarchy of Worker types. To instantiate those you can just use a standalone factory class, you don't need an abstract factory here. For example this would be sufficient:
public class WorkerFactory {
public Worker createWorker(String workerType) {
switch (workerType) {
case "Electrician": return new Electrician();
case "Mason": return new Mason();
}
}
}
The abstract factory pattern is more elaborate, and allows injecting different concrete factories for related hierarchies of objects, so that the client doesn't need to be aware of the difference. For example you could have an abstract TransportationFactory:
interface Transportation {
void travelTo(String destination);
}
interface TransportationFactory {
Transportation simple();
Transportation luxurious();
}
And two concrete implementations (matching two different but similar class hierarchies):
class WaterTransportationFactory {
Transportation simple() {
return new Kayak();
}
Transportation luxurious() {
return new Yacht();
}
}
And:
class LandTransportationFactory {
Transportation simple() {
return new Bike();
}
Transportation luxurious() {
return new RaceCar();
}
}
The benefit of this pattern is that the client can be configured to use water or land transportation (or a new air transportation that is added later) without the need to undergo any changes:
class Client {
private TransportationFactory transportationFactory;
public Client(TransportationFactory transportationFactory) {
this.transportationFactory = transportationFactory;
}
public void travel(String destination) {
transportationFactory.simple().travelTo(destination);
}
public void travelInStyle(String destination) {
transportationFactory.luxurious().travelTo(destination);
}
}
EDIT: You could change the simple/luxurious methods to match the style of your example with the getWorkerType method. I prefer to avoid the conditional logic if possible and let the created classes determine their availability themselves. This decouples even further, allowing hierarchy members to be added with minimal code changes:
enum TransportationType {
SIMPLE, LUXURIOUS
}
interface Transportation {
void travelTo(String destination);
// allow the class to specify its own type
TransportationType getType();
}
// intermediate interface to distinguish Water from Land
interface WaterTransportation extends Transportation {
}
class Kayak implements WaterTransportation {
void travelTo(String destination) {
// splash splash
}
TransportationType getType() {
return TransportationType.SIMPLE;
}
}
class WaterTransportationFactory {
private WaterTransportation[] waterTransportations;
// Inject all available beans implementing WaterTransportation
// e.g. using Spring or some other dependency injection mechanism
public WaterTransportationFactory(WaterTransportation[] waterTransportations) {
this.waterTransportations = waterTransportations;
}
public Transportation create(TransportationType type) {
for(WaterTransportation waterTransportation : waterTransportations) {
if (waterTransportation.getType() == type) {
// we are returning the same instance every time
// this could be ok for singleton beans
// but if you really need a fresh instance you could use builders (see below)
return waterTransportation;
}
}
throw new IllegalArgumentException("No implementation for WaterTransportation type=" + type);
}
}
An alternative with builders:
KayakBuilder implements WaterTransportationBuilder {
KayakBuilder name(String name) { ... };
KayakBuilder weight(String weightInKg) { ... };
KayakBuilder year(String yearBuilt) { ... };
KayakBuilder speed(String averageSpeed) { ... };
Kayak build() { return kayak; }
}
For more on Builders see this full exposition of the Builder pattern
class WaterTransportationFactory {
private WaterTransportationBuilder[] builders;
// Inject all available WaterTransportationBuilders
// e.g. using Spring or some other dependency injection mechanism
public WaterTransportationFactory(WaterTransportationBuilder[] builders) {
this.builders = builders;
}
// extra arguments can be passed to build the instance
public Transportation create(TransportationType type, String name, int weightInKg, int yearBuilt, int averageSpeed) {
for(WaterTransportationBuilder builder: builders) {
if (builder.getType() == type) {
return builder
.name(name)
.weight(weightInKg)
.year(yearBuilt)
.speed(averageSpeed)
.build();
}
}
throw new IllegalArgumentException("No implementation for WaterTransportation type=" + type);
}
}
I try to learn Spring framework. I have some questions.
I create one controller and few class. Here is the controller:
#Controller
#RequestMapping("/man")
public class manController {
private SwordImp Sword = new SwordImp();
private GunImp Gun = new GunImp();
private String mainWeapon;
private String subWeapon;
#RequestMapping(value = "set/{weapon:[a-z A-Z 0-9]+}", method = RequestMethod.GET)
public String setWeapon(#PathVariable String weapon, Model model){
System.out.println(weapon);
if(weapon.equals("gun")){
Gun.set(weapon);
mainWeapon = Gun.getWeapon();
subWeapon = Gun.getSubWeapon();
}else{
if(weapon.equals("sword")){
Sword.set(weapon);
mainWeapon = Sword.getWeapon();
subWeapon = Sword.getSubWeapon();
}else{
mainWeapon = "no weapon";
subWeapon = "no sub weapon";
}
}
model.addAttribute("weapon_status", mainWeapon);
model.addAttribute("sub_weapon_status", subWeapon);
return "man/index";
}
}
I also create some class.
Weapon interface
public interface Weapon {
public void set(String weaponName);
public String getWeapon();
public String getSubWeapon();
}
Sword class
public class SwordImp implements Weapon {
private String weaponName = null;
public void set(String weapon) {
this.weaponName = "fire "+weapon;
}
public String getWeapon() {
return this.weaponName;
}
public String getSubWeapon() {
return "no sub weapon";
}
}
Gun Class
public class GunImp implements Weapon {
private String weaponName = null;
private String bullet = null;
public void set(String weapon) {
this.weaponName = "ice "+weapon;
this.bullet = "need bullet";
}
public String getWeapon() {
return this.weaponName;
}
public String getSubWeapon() {
return this.bullet;
}
}
The questions I have:
If I don't implement the Weapon class in the gun Class and sword class as below, it seems like that the function still can work... So why do we need to use interface?
Sword class
public class SwordImp {...}
Gun Class
public class GunImp {...}
I try to put the all of class into the repositories folder. Is this correct path? or do I need to put them into model folder?
At first, I try to put the weaponName variable and bullet variable that in the Gun class and Sword class into the weapon interface, so I don't need to declare them in every class, like this:
Weapon interface
public interface Weapon {
private String weaponName = null;
private String bullet = null;
public void set(String weaponName);
public String getWeapon();
public String getSubWeapon();
}
Sword class
public class SwordImp implements Weapon {
public void set(String weapon) {
this.weaponName = "fire "+weapon;
this.bullet = "no sub weapon";
}
public String getWeapon() {
return this.weaponName;
}
public String getSubWeapon() {
return this.bullet;
}
}
Gun Class
public class GunImp implements Weapon {
public void set(String weapon) {
this.weaponName = "ice "+weapon;
this.bullet = "need bullet";
}
public String getWeapon() {
return this.weaponName;
}
public String getSubWeapon() {
return this.bullet;
}
}
But this seems like that is wrong... what is the reason?
You can use the Abstract factory pattern to inject the specific weapon during runtime rather than hardcoding them in controller.
Consider that you have 100 different weapons, It will be hard to add all the weapon implementation class to the controller. You can find the example and implementation of this pattern in google. It is considered to be a best practice.
Try to follow the best practice. It will help you to learn better and write neat and maintainable code. yes moving to the model folder is better.
In OOP it is important to create your object well defined. Interface can only have the constant fields and methods. The state defined in the interface cannot be changed.
I have two classes:
DocumentState and ElectronicDocumentState.
They look like this:
public class DocumentState extends LabeledEnum {
public static final DocumentState CREATED = new DocumentState("created");
// ..... - 15 other statuses
}
ElectronicDocumentState also extends LabeledEnum and has its own statuses, some are common like created, other are unique.
Then I have plenty of methods in code that take DocumentState as a parameter or are returning DocumentState as result. Now they should work also with ElectronicDocumentState.
Also I have plenty places that do:
if (DocumentSate.CREATED.equals(doc.getState()) || DocumentState.DELETED.equals(doc.getState())) {
//do something with document
}
I want to avoid 'if' and avoid creating new methods for ElectronicDocumentState as more state can appear in future.
How would you do that ?
So using the below example, how would you refactor it so it could work with DocumentState and ElectronicDocumentState? I have plenty of such methods that now should also work with ElectronicDocumentState. Someone asks us to mix electronicDocuments with documents in business logic:
private DocumentState getDocumentStateForDetails(Document doc, DocumentState sourceState) {
if (DocumentState.CREATED.equals(doc.getDocumentState())) {
if (sourceState.equals(DocumentState.CREATED)) {
return DocumentState.CREATED;
} else {
return DocumentState.BLOCKED;
}
} else {
return sourceState.getDocumentState();
}
}
If you are worrying about further extension of your state model, I'd suggest you to think about using inheritance instead of if/switch and instanceof by splitting the document class to Value and State, for instance. If you have the same set of available actions for any state of document, just use classical State pattern, otherwise, each State may have its own set of available actions:
public class Document {
public static CreatedDocument<Document> create(String author) {
return new CreatedDocument<>(new Document(author));
}
private String author;
//...
private Document(String author) {
//...
}
}
public class ElectronicDocument extends Document {
public static CreatedElectronicDocument create(String author, String url) {
return new CreatedElectronicDocument(author, url);
}
private String url;
//...
public ElectronicDocument(String author, String url) {
//...
}
//...
}
public interface DocumentState<T extends Document> {
T getDocument();
char getCode(); // might be needed for something like logging?
}
public abstract class AbstractDocumentState<T extends Document> implements DocumentState<T> {
protected final T document;
protected AbstractDocumentState(T document) {
this.document = document;
}
#Override
public T getDocument() {
return document;
}
}
public class CreatedDocument<T extends Document> extends AbstractDocumentState<T> {
public CreatedDocument(T document) {
super(document);
}
#Override
public char getCode() {
return 'C';
}
public DocumentState<T> delete() {
return new DeletedDocument<>(document);
}
}
public class CreatedElectronicDocument extends CreatedDocument<ElectronicDocument> {
public CreatedElectronicDocument(String author, String url) {
super(new ElectronicDocument(author, url));
}
public DownloadElectronicDocument download() {
return new DownloadElectronicDocument(document);
}
}
public class DownloadElectronicDocument extends AbstractDocumentState<ElectronicDocument> {
public DownloadElectronicDocument(ElectronicDocument document) {
super(document);
// DO DOWNLOAD HERE
}
#Override
public char getCode() {
return 'L';
}
public DocumentState<ElectronicDocument> delete() {
return new DeletedDocument<>(document);
}
}
public class DeletedDocument<T extends Document> extends AbstractDocumentState<T> {
public DeletedDocument(T document) {
super(document);
// DO DELETE HERE
}
#Override
public char getCode() {
return 'D';
}
}
Not sure you need getCode() now, when you use inheritance. BTW, switch works faster than a set of if/else if.
If you'd like to stay with your enum classes, why wouldn't to extract common states to a super class?
public class CommonDocumentState extends LabeledEnum {
public static final CommonDocumentState CREATED = new CommonDocumentState ("created");
..... - n other statuses
}
public class DocumentState extends CommonDocumentState {
..... - m other statuses
}
public class ElectronicDocumentState extends CommonDocumentState {
..... - k other statuses
}
That's the only way to have such generic rules like
if (DocumentSate.CREATED.equals(doc.getState()) || DocumentState.DELETED.equals(doc.getState())) {
//do something with document
}
be working for both DocumentState and ElectronicDocumentState.
There are not enough information about your domain to provide a final answer, but I have some suggestions:
it seems that both DocumentState and ElectronicDocumentState inherit from LabeledEnum; if you want to manage both of them in your methods you can make ElectronicDocumentState inherit from DocumentState of it's feasibile merge the two classes. This will allow to pass ElectronicDocumentState or DocumentState in your methods and perhaps solve your second question.
if you want to avoid the if you can build a list of allowed method and check against the list, something like:
L
public class YourClass {
List<DocumentSate> allowedStates=//init here or in constructor
....
public void yourMethod(....) {
if (allowedStates.contains(doc.getState())) {
//do something
}
}
allowedStates may be factored out in separate class if it is a common case. If you find the refactoring feasible, may be you can check if you are dealing with a finite state machine and implement it (with the help of some exisiting libraries).
I am trying ot understand how to apply a the simple factory pattern to an assigment I have but I do not understand how to do it.
This is the request: Apply the Simple Factory pattern that creates the appropriate Strategy object.
Remember, this is a Simple Factory pattern. Draw the UML diagram of the new
design.
We already implemented the strategy pattern but I do not understand how to apply the simple factory pattern to the code. I understand that the simple factory pattern is supposed to provide encapsulation for the creation of the object but I do not see how the examples I have found show how to apply to this. Any help would be appreciated.
EDIT: Updated code
EDIT: Changed code to make use of polymorphism
package Client;
import domain.Loan;
import factory.StrategyFactory;
import strategy.ComplexLoan;
import strategy.ICapitalStrategy;
public class Client {
public static void main(String[] args){
Loan complexLoan = new Loan(2.2, 2, 3.3, 4.4, 5, 6, 7, StrategyFactory.getComplexStrategy());
System.out.print("hello");
}
}
package factory;
import strategy.ComplexLoan;
import strategy.ICapitalStrategy;
import strategy.RevolvingLoan;
import strategy.TermLoan;
public class StrategyFactory {
/*
public static ICapitalStrategy getStrategy(String type) {
if (type.equals("Complex")){
return new ComplexLoan();
}
else if (type.equals("Revolving")){
return new RevolvingLoan();
}
else if (type.equals("Term")){
return new TermLoan();
}
return null;
}
*/
public static ICapitalStrategy getComplexStrategy() {
return new ComplexLoan();
}
public static ICapitalStrategy getRevolvingStrategy() {
return new RevolvingLoan();
}
public static ICapitalStrategy getTermStrategy() {
return new TermLoan();
}
}
package domain;
import strategy.ICapitalStrategy;
public class Loan {
private ICapitalStrategy strategy;
double commitment;
int duration;
double riskFactor;
double unusedPercentage;
int outstandingRiskAmount;
int unusedRiskAmount;
double unusedRiskFactor;
double capital;
public Loan(double commit, int dura, double rskFact, double unusedPer,
int outStandRskAmt, int unusedRskAmt, double unusedRskFac,
ICapitalStrategy strat) {
this.commitment = commit;
this.duration = dura;
this.riskFactor = rskFact;
this.outstandingRiskAmount = outStandRskAmt;
this.unusedRiskAmount = unusedRskAmt;
this.unusedRiskFactor = unusedRskFac;
this.strategy = strat;
}
public double CalculateCapital() {
return strategy.CapitalLoan(this);
}
public double getCommitment() {
return commitment;
}
public void setCommitment(double c) {
commitment = c;
}
public int getDuration() {
return duration;
}
public void setDuration(int dur) {
duration = dur;
}
public double getRiskFactor() {
return riskFactor;
}
public void setRiskFactor(double rskFac) {
riskFactor = rskFac;
}
public double getUnusedPercentage() {
return unusedPercentage;
}
public void setUnusedPercentage(double unusedPercent) {
unusedPercentage = unusedPercent;
}
public double getOutstandingRiskAmount() {
return outstandingRiskAmount;
}
public void setOutstandingRiskAmount(int outStandingRskAmt) {
outstandingRiskAmount = outStandingRskAmt;
}
public double getUnusedRiskAmount() {
return unusedRiskAmount;
}
public void setUnusedRiskAmount(int UnusedRskAmt) {
unusedRiskAmount = UnusedRskAmt;
}
public double getUnusedRiskFactor() {
return unusedRiskFactor;
}
public void setUnusedRiskFactor(double unusedRskFac) {
unusedRiskFactor = unusedRskFac;
}
public Loan(ICapitalStrategy strategy) {
this.strategy = strategy;
}
/*public double executeStrategy() {
return this.strategy.CapitalLoan(this);
}
*/
}
package strategy;
import domain.Loan;
public class ComplexLoan implements ICapitalStrategy {
#Override
public double CapitalLoan(Loan l) {
return ((l.getOutstandingRiskAmount() * l.getDuration() * l.getRiskFactor()) + (l.getUnusedRiskAmount()
* l.getDuration() * l.getUnusedRiskFactor() ));
}
}
package strategy;
import domain.Loan;
public interface ICapitalStrategy {
public double CapitalLoan(Loan l);
}
package strategy;
import domain.Loan;
public class RevolvingLoan implements ICapitalStrategy {
#Override
public double CapitalLoan(Loan l) {
return (l.getCommitment() * l.getUnusedPercentage() * l.getDuration() *l.getRiskFactor());
}
}
package strategy;
import domain.Loan;
public class TermLoan implements ICapitalStrategy {
public TermLoan() {
}
public double CapitalLoan(Loan l) {
return (l.getCommitment() * l.getDuration() * l.getRiskFactor());
}
}
Here's a likely helpful bit about Simple Factory Pattern[1]:
The simple factory isn't actually a pattern; it's more of a design principle. The simple factory encapsulates the object creation code, but keeps control over how the object is created. Simple factories are often designed as a class with a static method (aka static factory) that returns the object requested.
Here's an example, not suited directly to your example in order to make you think a bit hard for your homework :)
interface Foo{
double calculateStuff();
}
class MyClass implements Foo{
#Override
public double calculateStuff(){
//logic goes here
}
}
class MyFactory {
public static double getCalculatedStuff(){
return new MyClass().calculateStuff();
}
}
class RunCode {
public static void main(String[] args){
double stuff = MyFactory.getCalculatedStuff();
}
}
[1] - Learning Design Patterns - Factory Pattern
EDIT:
class LoanFactory{
public static double getComplexLoan(Loan l){
return new ComplexLoan().CapitalLoan(l);
}
}
another way (which has its uses, but in this case I prefer the method above):
class ComplexLoan implements ICapitalStrategy{
private ComplexLoan(){
}
public static double getLoan(Loan l){
return new ComplexLoan().CapitalLoan(l);
}
}
or this option that explicitly displays polymorphism:
class LoanFactory{
public static ICapitalStrategy getComplexLoan(){
return new ComplexLoan();
}
}
One other thing that is important to note: convention says method names should start with a lowercase letter, so your CapitalLoan() would be capitalLoan().
Also, there's no need to prefix your interfaces with an I, so your ICapitalStrategy would become CapitalStrategy.
In the following example. The "Document" is abstract class and "html" document. "MyDocument" and "pdf" are concrete class. As long as you provide parameter with valid string, you will get the corresponding concrete class. For example if you put "pdf" as a parameter, you will get pdf document. Document type is all you need to accept whatever type of documents you want to create.
public Document CreateDocument(String type){
if (type.isEqual("html"))
return new HtmlDocument();
if (type.isEqual("proprietary"))
return new MyDocument();
if (type.isEqual("pdf"))
return new PdfDocument ();
}
There is a better documented article thread in
Examples of GoF Design Patterns in Java's core libraries
public interface PaymentMethod {
public void makePayment();
}
class CreditCard implements PaymentMethod {
public void makePayment() {
System.out.println("Payment through credit card...");
}
}
class NetBanking implements PaymentMethod {
public void makePayment() {
System.out.println("Payment through net banking...");
}
}
public class PaymentMethodFactory {
public static PaymentMethod getPaymentMethod(String method) {
if ("creditcard".equalsIgnoreCase(method)) {
return new CreditCard();
} else if ("netbanking".equalsIgnoreCase(method)) {
return new NetBanking();
} else {
throw new IllegalArgumentException("Payment method not supported!");
}
}
}
public class SimpleFactoryTest {
public static void main(String[] args) {
PaymentMethodFactory factory = new PaymentMethodFactory();
PaymentMethod paymentMethod = factory.getPaymentMethod("creditcard");
paymentMethod.makePayment();
}
}