I've made a basic function to check a password complies with various business rules. Has an upper case character, has a number etc.
I'd like to make this function more flexible and configurable by toggling these options on and off as desired. The only way I can think of to do this is as so:
public static boolean isPasswordValid(String pwd, boolean checkUpper, boolean checkLower, boolean checkNum) {
boolean hasUppercase = !pwd.equals(pwd.toLowerCase(Locale.getDefault()));
boolean hasLowercase = !pwd.equals(pwd.toUpperCase(Locale.getDefault()));
boolean hasNumeric = pwd.matches(".*\\d+.*");
boolean isValid = false;
if(checkUpper){
if(hasUppercase) {
isValid = true;
}else{
return isValid;
}
}
return isValid;
}
I feel like there is a much better method, using Enums or something. I'd like to be able to pass in the password and just one extra parameter to act as a flag to enable various checks. Inevitably I'll need to add more as time goes on.
If I were to use enums, by my way of thinking, I'd have to define one eNum for every possible case. i.e. upper, upper_and_lower, upper_and_numeric. Which would get very complex if I had to add in more options.
Any ides and suggestions would be most welcome. Thanks.
You can use EnumSet, which is a specialized set for enums.
public static enum Validation {
UPPER, LOWER, DIGIT //etc.
}
public static boolean isPasswordValid(String pwd, EnumSet<Validation> validations) {
//...
}
Then, you can use any combination of validations by adding necessary values to the set. Example:
EnumSet<Validation> validation = EnumSet.of(Validation.UPPER, Validation.LOWER);
if (isPasswordValid(pass, validation)) {
//...
}
You could do it with regex:
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$
You validate for password with all three combinations (number, upper, lower case alphabets)
String pwd = "aaaaaaabbbbCCCC43333333222111";
if (pwd.matches("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).*$")) {
System.out.println("It has all three combinations");
} else {
System.out.println("Invalid password");
}
Output:
It has all three combinations
Less Simple, but really flexible, using method chaining:
public abstract class Clause {
public abstract boolean match(string value);
}
public final class UpperCaseClause extends Clause {
#Override
public boolean match(string value) {
return !value.equals(value.toLowerCase(Locale.getDefault()));
}
}
public final class LowerCaseClause extends Clause {
#Override
public override boolean match(string value) {
return !value.equals(value.toUpperCase(Locale.getDefault()));
}
}
public final class NumericClause extends Clause {
#Override
public override boolean match(string value) {
return value.matches(".*\\d+.*");
}
}
public final class Validator {
private List<Clause> clauses;
public Validator() {
clauses = new ArrayList<Clause>();
}
public Validator addClause(Clause toAdd) {
clauses.add(toAdd);
return this;
}
public boolean valid(string value) {
boolean isValid = true;
for(clause in clauses) {
isValid &= clause.match(value);
if (!isValid) {
break;
}
}
return isValid;
}
}
[... you could create this anywhere and cache it]
Validator allValidator = new Validator().addClause(new UpperCaseClause())
.addClause(new LowerCaseClause())
.addClause(new NumericClause());
[...]
public static boolean isPasswordValid(String pwd, Validator validator) {
validator.valid(pwd);
}
[... then pass in the validator you wish to use]
isPasswordValid(pwd, allValidator);
[...]
Related
I want to remove multiple conditions from the if statement.
How can I achieve that?
I think switch is not what I'm looking for. I'm thinking of something that respect the Open close principal or using an interface to call the different boolean method.
Now I'm using :
if (utilisateur.isAdmin() || utilisateur.isWebMaster() || utilisateur.isAdministrateurLiferay() || utilisateur.estResponsableCommercial()) {
Example of a method :
public boolean estResponsableCommercial() {
return roles.stream().anyMatch(Role::isResponsableCommercial);
}
you can try with an Enum:
public enum Role {
public abstract boolean check(User user);
ADMIN {
public boolean check(User user) {
return user.isAdmin();
}
},
WEBMASTER {
public boolean check(User user) {
return user.isWebMaster();
}
};
public boolean checkRoles(User user) {
for(Role role : Role.values()) {
if(role.check(user)) {
return true;
}
}
return false;
}
}
It seems like you're looking for a way to combine predicates in order to use them in operations like anyMatch.
If so, you can achieve this using static method Predicate.or():
#SafeVarargs
public static <T> Predicate<T> combineWithOr(Predicate<T>... predicates) {
return Arrays.stream(predicates).reduce(t -> true, Predicate::or); // if `predicates` is empty then method would return `true`, another way of expressing this: `reduce(Predicate::or).orElse(t -> true)`
}
And that how you can apply it to obtain a composite predicate:
Predicate<UserRole> combinedPredicate = combineWithOr(
UserRole::isAdmin,
UserRole::isWebMaster,
UserRole::isAdministrateurLiferay,
UserRole::estResponsableCommercial
);
public static boolean hasMatchingRole(Collection<UserRole> roles,
Predicate<UserRole> predicate){
return roles.stream().anyMatch(predicate);
}
private static boolean isEstResponsableCommercial(List<String> roles, String roleYouLookingFor) {
return roles.stream().anyMatch(r->r.equals(roleYouLookingFor));
}
Signature of anyMatch is:
boolean anyMatch(Predicate<? super T> predicate)
I am trying to map values from one enum to the other based on some calculation or conditional logic that I need to perform to set the correct enum value for the class variable. How can I do this without using too many if/else, switch statements?
Enum BRAND {
MINI, FERRARI, PAGANI
}
and another enum
Enum ENGINE {
LEVEL1, LEVEL2, LEVEL3
}
And I have a class like :
Class Car() {
int model;
int year;
Engine engine;
// I want to calculate set the engine depending on the brand based on conditional logic
public carEngineCalculator (Brand b) {
Car mycar = new Car();
if (mycar.isSuperCar(b) {
if (mycar.isCrazyGood(b)) {
mycar.engine = ENGINE.LEVEL1;
} else {
mycar.engine = ENGINE.LEVEL2;
}
} else {
mycar.engine = ENGINE.LEVEL3;
}
... //And the conditions can be more complex
}
public boolean isSuperCar(Brand b) {
if (b.FERRARI || b.PAGANI) {
return true;
}
return false;
}
public boolean isCrazyGood(Brand b) {
return ...;
}
}
There can be more than one such conditions that need to be checked in order to set the values and I want to avoid nasty if/else/switch statements as shown above. Is there a more functional way of doing this.
Using predicates as I said would look like this:
public enum Brand {
MINI,
FERRARI,
PAGANI
}
public enum Engine {
LEVEL1,
LEVEL2,
LEVEL3
}
public class Entry {
public final Predicate<Car> pred;
public final Engine engine;
public Entry(Predicate<Car> pred, Engine engine) {
this.pred = pred;
this.engine = engine;
}
}
public class Car {
int model;
int year;
Engine engine;
public void carEngineCalculator(Brand b) {
Car mycar = new Car();
List<Entry> cases = new ArrayList<>();
cases.add(new Entry(c -> c.isSuperCar(b) && c.isCrazyGood(b), Engine.LEVEL1));
cases.add(new Entry(c -> c.isSuperCar(b) && !c.isCrazyGood(b), Engine.LEVEL2));
cases.add(new Entry(c -> !c.isSuperCar(b), Engine.LEVEL3));
mycar.engine = cases.stream().filter(x -> x.pred.test(mycar)).findFirst().get().engine;
}
public boolean isSuperCar(Brand b) {
if ((b == Brand.FERRARI) || (b == Brand.PAGANI)) {
return true;
}
return false;
}
public boolean isCrazyGood(Brand b) {
return false;
}
}
You create a List with Predicates and Results and use stream, filter and findFirst to go through the list and find the right result. If the conditions are simpler than you don't need predicates and test it a little bit different.
If the mapping is one-to-one for Brand and Engine, you could do something like this:
enum Brand {
MINI(Engine.LEVEL1),
FERRARI(Engine.LEVEL2),
PAGANI(Engine.LEVEL3);
private final Engine engine;
private Brand(Engine engine) {
this.engine = engine;
}
public final Engine getEngine() {
return engine;
}
}
Another option:
enum Brand {
MINI(false, false),
FERRARI(true, true),
PAGANI(false, true);
private final boolean superCar;
private final boolean crazyGood;
private Brand(boolean superCar, boolean crazyGood) {
this.superCar = superCar;
this.crazyGood = crazyGood;
}
public final Engine getEngine() {
if (superCar) {
return (crazyGood) ? Engine.LEVEL1 : Engine.LEVEL2;
}
return Engine.LEVEL3;
}
}
If the mapping is not one-to-one and you need to somehow dynamically calculate the engine based on some parameters, you could also use this:
enum Brand {
MINI {
#Override
public Engine getEngine(boolean superCar, boolean crazyGood) {
return (superCar && crazyGood) ? Engine.LEVEL1 : Engine.LEVEL2;
}
},
FERRARI {
#Override
public Engine getEngine(boolean superCar, boolean crazyGood) {
return superCar ? Engine.LEVEL1 : Engine.LEVEL3;
}
},
PAGANI {
#Override
public Engine getEngine(boolean superCar, boolean crazyGood) {
return Engine.LEVEL3;
}
};
public abstract Engine getEngine(boolean superCar, boolean crazyGood);
}
Or something like this, where you have some defaults and override just for special cases:
enum Brand {
MINI,
FERRARI {
#Override
public Engine getEngine(boolean superCar, boolean crazyGood) {
return superCar ? Engine.LEVEL1 : Engine.LEVEL3;
}
},
PAGANI;
public Engine getEngine(boolean superCar, boolean crazyGood) {
return Engine.LEVEL3;
}
}
There are a lot of possibilities using just enums, which I actually prefer to complex if/else or switch statements. Of course it depends on what exactly you want to do and since there is not much info provided, I cannot really give the best answer. Hope that this helps you.
First, move your isSuperCar and isCrazyGood methods into Brand, rather than have them take a Brand parameter. You could similarly add a static factory method to Engine that encapsulates the logic you're trying to encode. That doesn't wholly avoid the "nasty if/else/switch statements", but it's likely to be a lot more readable.
For example:
public Car(Brand b) {
this.engine = Engine.forBrand(b);
}
and then:
enum Engine {
LEVEL1, LEVEL2, LEVEL3
public static Engine forBrand(Brand b) {
if (b.isSuperCar()) {
return b.isCrazyGood() ? LEVEL1 : LEVEL2;
}
return LEVEL3;
}
}
Note also that your isSuperCar method can simply be:
return b.equals(Brand.FERRARI) || b.equals(Brand.PAGANI);
There's never a need to write if (...) return true; else return false; or anything similar - just use the boolean expression in the if statement directly.
I would probably store the brand in the Car class, but that is another issue. I would have a static map in the Car class that keeps track of which engines go with each brand (as Ralf Renz suggested):
Class Car {
int model;
int year;
Engine engine;
static Map<Brand, Engine> carEngineMap = new HashMap<>();
public static void setBrandEngine(Brand b, Engine e) {
carEngineMap.put(b, e);
}
// I want to calculate set the engine depending on the brand based on conditional logic
public carEngineCalculator (Brand b) {
Car mycar = new Car();
mycar.engine = carEngineMap.get(b);
}
public boolean isSuperCar(Brand b) {
if (b.FERRARI || b.PAGANI) {
return true;
}
return false;
}
public boolean isCrazyGood(Brand b) {
return ...;
}
}
You would then put the conditions in separately for each brand, like
Car.setBrandEngine(Brand.FERRARI, Engine.LEVEL2);
Car.setBrandEngine(Brand.PAGANI, Engine.LEVEL1);
...
create enum with predicates, CONDITION(brand, engine, condition) and supply your condition there. Afterwards:
Conditions.values().foreach(condition -> {
condition.isApplicable(variblesDto) ? return condition.apply() : continue;
});
and you update your Enum anytime you need new condition. It will also go in order of Enum, so you could play with that
I need to build a process which will validate a record against ~200 validation rules. A record can be one of ~10 types. There is some segmentation from validation rules to record types but there exists a lot of overlap which prevents me from cleanly binning the validation rules.
During my design I'm considering a chain of responsibility pattern for all of the validation rules. Is this a good idea or is there a better design pattern?
Validation is frequently a Composite pattern. When you break it down, you want to seperate the what you want to from the how you want to do it, you get:
If foo is valid
then do something.
Here we have the abstraction is valid -- Caveat: This code was lifted from currrent, similar examples so you may find missing symbology and such. But this is so you get the picture. In addition, the
Result
Object contains messaging about the failure as well as a simple status (true/false).
This allow you the option of just asking "did it pass?" vs. "If it failed, tell me why"
QuickCollection
and
QuickMap
Are convenience classes for taking any class and quickly turning them into those respected types by merely assigning to a delegate. For this example it means your composite validator is already a collection and can be iterated, for example.
You had a secondary problem in your question: "cleanly binding" as in, "Type A" -> rules{a,b,c}" and "Type B" -> rules{c,e,z}"
This is easily managed with a Map. Not entirely a Command pattern but close
Map<Type,Validator> typeValidators = new HashMap<>();
Setup the validator for each type then create a mapping between types. This is really best done as bean config if you're using Java but Definitely use dependency injection
public interface Validator<T>{
public Result validate(T value);
public static interface Result {
public static final Result OK = new Result() {
#Override
public String getMessage() {
return "OK";
}
#Override
public String toString() {
return "OK";
}
#Override
public boolean isOk() {
return true;
}
};
public boolean isOk();
public String getMessage();
}
}
Now some simple implementations to show the point:
public class MinLengthValidator implements Validator<String> {
private final SimpleResult FAILED;
private Integer minLength;
public MinLengthValidator() {
this(8);
}
public MinLengthValidator(Integer minLength) {
this.minLength = minLength;
FAILED = new SimpleResult("Password must be at least "+minLength+" characters",false);
}
#Override
public Result validate(String newPassword) {
return newPassword.length() >= minLength ? Result.OK : FAILED;
}
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Here is another we will combine with
public class NotCurrentValidator implements Validator<String> {
#Autowired
#Qualifier("userPasswordEncoder")
private PasswordEncoder encoder;
private static final SimpleResult FAILED = new SimpleResult("Password cannot be your current password",false);
#Override
public Result validate(String newPassword) {
boolean passed = !encoder.matches(newPassword,user.getPassword());
return (passed ? Result.OK : FAILED);
}
#Override
public String toString() {
return this.getClass().getSimpleName();
}
}
Now here is a composite:
public class CompositePasswordRule extends QuickCollection<Validator> implements Validator<String> {
public CompositeValidator(Collection<Validator> rules) {
super.delegate = rules;
}
public CompositeValidator(Validator<?>... rules) {
super.delegate = Arrays.asList(rules);
}
#Override
public CompositeResult validate(String newPassword) {
CompositeResult result = new CompositeResult(super.delegate.size());
for(Validator rule : super.delegate){
Result temp = rule.validate(newPassword);
if(!temp.isOk())
result.put(rule,temp);
}
return result;
}
public static class CompositeResult extends QuickMap<Validator,Result> implements Result {
private Integer appliedCount;
private CompositeResult(Integer appliedCount) {
super.delegate = VdcCollections.delimitedMap(new HashMap<PasswordRule, Result>(), "-->",", ");
this.appliedCount = appliedCount;
}
#Override
public String getMessage() {
return super.delegate.toString();
}
#Override
public String toString() {
return super.delegate.toString();
}
#Override
public boolean isOk() {
boolean isOk = true;
for (Result r : delegate.values()) {
isOk = r.isOk();
if(!isOk)
break;
}
return isOk;
}
public Integer failCount() {
return this.size();
}
public Integer passCount() {
return appliedCount - this.size();
}
}
}
and now a snippet of use:
private Validator<String> pwRule = new CompositeValidator<String>(new MinLengthValidator(),new NotCurrentValidator());
Validator.Result result = pwRule.validate(newPassword);
if(!result.isOk())
throw new PasswordConstraintException("%s", result.getMessage());
user.obsoleteCurrentPassword();
user.setPassword(passwordEncoder.encode(newPassword));
user.setPwExpDate(DateTime.now().plusDays(passwordDaysToLive).toDate());
userDao.updateUser(user);
Chain of responsibility implies that there is an order in which the validations must take place. I would probably use something similar to the Strategy pattern where you have a Set of validation strategies that are applied to a specific type of record. You could then use a factory to examine the record and apply the correct set of validations.
Consider this case.
You have a class which you cannot change or extend in any way.
public class Foo {
...
private Boolean bar;
...
}
You need to edit the fields of that class via BeanEditor, but the logic behind that class allows and uses the fact that Boolean can have, so to say, 3 states: null, true and false.
Tapestry will, however, give you a checkbox with only 2 options, true or false.
So, people online suggest that you convert your Boolean type property to BooleanExtendedEnum type property which could represent three way logic.
public enum BooleanExtendedEnum {
UNDEFINED(null),
TRUE(Boolean.TRUE),
FALSE(Boolean.FALSE);
private Boolean booleanValue;
private static Map<Boolean, BooleanExtendedEnum> booleanToExtendedMap = new HashMap<Boolean, BooleanExtendedEnum>();
static {
for (BooleanExtendedEnum be : BooleanExtendedEnum.values()) {
booleanToExtendedMap.put(be.booleanValue, be);
}
}
private BooleanExtendedEnum(Boolean booleanValue) {
this.booleanValue = booleanValue;
}
public Boolean getBooleanValue() {
return booleanValue;
}
public static BooleanExtendedEnum getBooleanExtendedValue(Boolean booleanInput) {
return booleanToExtendedMap.get(booleanInput);
}
}
Since you cannot change your Foo class, you'll need to create a coercer for Boolean <=> BooleanExtendedEnum.
Coercion<Boolean, BooleanExtendedEnum> threeWayBooleanToExtended = new Coercion<Boolean, BooleanExtendedEnum>() {
#Override
public BooleanExtendedEnum coerce(Boolean input) {
if (input == null) {
return BooleanExtendedEnum.UNDEFINED;
} else {
return BooleanExtendedEnum.getBooleanExtendedEnumValue(input);
}
}
};
Coercion<BooleanExtendedEnum, Boolean> threeWayExtendedToBoolean = new Coercion<BooleanExtendedEnum, Boolean>() {
#Override
public Boolean coerce(BooleanExtendedEnum input) {
if (input == null) {
return null;
} else {
return input.getBooleanValue();
}
}
};
configuration.add(new CoercionTuple<Boolean, BooleanExtendedEnum>(Boolean.class, BooleanExtendedEnum.class, threeWayBooleanToExtended));
configuration.add(new CoercionTuple<BooleanExtendedEnum, Boolean>(BooleanExtendedEnum.class, Boolean.class, threeWayExtendedToBoolean));
Let's assume you have done something as simple as this in your BeanEditor in your tml:
<p:bar>
<div class="t-beaneditor-row">
<label>Bar Value</label>
<t:select t:id="fooBar" t:value="foo.bar" t:model="booleanExtendedSelectModel" t:blankOption="NEVER"/>
</div>
</p:bar>
... and provided the SelectModel like this:
public SelectModel getBooleanExtendedSelectModel() {
return new EnumSelectModel(BooleanExtendedEnum.class, messages);
}
Tapestry will create a drop-down list with three options
Undefined
True
False
However, the real Boolean values it will coerce those displayed values to will be
Undefined -> true
True -> true
False -> false
How can one achieve the desired effect (Undefined -> null), with limitations of not changing the class or wrapping it in another class which has Boolean type fields replaced with BooleanExtendedEnum type ones or using any other "hacky" solution?
The "glue" between the BeanEditor and the backing bean is the BeanModel. BeanModels are created by the BeanModelSource which in turn uses PropertyConduitSource.
It's quite simple to decorate the PropertyConduitSource to use Ternary instead of Boolean.
eg
public class MyAppModule {
public PropertyConduitSource decoratePropertyConduitSource(final PropertyConduitSource old) {
return new PropertyConduitSource() {
public PropertyConduit create(Class rootType, String expression) {
PropertyConduit conduit = old.create(rootType, expression);
// you cound also check for conduit.getAnnotation(AllowNull.class)
// and then annotate your bean properties for a more granular approach
if (Boolean.class.equals(conduit.getPropertyType()) {
return new TernaryPropertyConduit(conduit);
}
return conduit;
}
}
}
}
public class TernaryPropertyConduit implements PropertyConduit {
private PropertyConduit delegate;
public getPropertyType() { return Ternary.class };
public set(Object instance, Object value) {
delegate.set(instance, ((Ternary) value).asBoolean());
}
public get(Object) {
Boolean bValue = (Boolean) delegate.get(instance);
return Ternary.valueOf(instance);
}
}
You could add a property to your page and use a custom block.
public enum Ternary {
TRUE(Boolean.TRUE), FALSE(Boolean.FALSE), UNDEFINED(null);
public static Ternary valueOf(Boolean value) { ... }
public Boolean asBoolean() { ... }
}
public class MyPage {
#Property
private Foo foo;
public Ternary getTernaryBar() {
return Ternary.valueOf(foo.getBar());
}
public void setTernaryBar(Ternary tBar) {
foo.setBar(tBar.asBoolean());
}
}
<t:beaneditor t:id="foo" exclude="bar" add="ternaryBar">
<p:ternaryBar>
<t:label for="ternaryBar"/>
<t:select t:id="ternaryBar" />
</p:ternaryBar>
</t:beaneditor>
I am creating a client side swing app that will have data provided by/from one of many data providers(brokers). The data providers however, have varying ways of perfoming same things e.g.
broker1's login method
public boolean doLogin(String username, String password);
broker2's login method
public int login(String username, String password,String sessionId);
For all providers the set of required actions is the same
e.g
login, getstatus, sendRequest, getData, logOff
(but they have different params and return types)
I took a look at the adapter pattern but am unfortunately not able to use it well as the required methods have different parameters.
Is the adapter pattern usable in this case? if so how?
If not what would be the best way of doing this?
Thanks.
Patterns are general guidelines (starting point) of best practices. Many developers "adapts" the patterns to their needs; the important thing is, then, if you must use a pattern, use it consistently throughout your whole application.
Now, to answer your question; yes the adapter pattern can very well be used in your situation. A possible solution (in the like) could be:
abstract class BrokerAbstract<T> {
private int errCode;
private String errMessage;
abstract public boolean login(String user, String pass, Map<String,Object> options);
abstract public int getStatus(Map<String,Object> options);
abstract public boolean sendRequest(Map<String,Object> options);
abstract public T getData(Map<String,Object> options);
abstract public boolean logOff(Map<String,Object> options);
protected void setError(int code, String message) {
this.errCode = code;
this.errMessage = message;
}
public int getErrorCode() { return this.errCode; }
public String getErrorMessage() { return this.errMessage; }
}
Then
class Broker1 extends BrokerAbstract<Object> {
private OriginalBroker1 original;
public boolean login(String user, String pass, Map<String,Object> options) {
return original.doLogin(user, pass); // ignore options
}
public boolean login(String user, String pass) {
return login(user, pass, null); // third parameters will be ignored
}
public int getStatus(Map<String,Object> options) { /*...*/ return 0; }
public boolean sendRequest(Map<String,Object> options) { /*...*/ return false; }
public Object getData(Map<String,Object> options) {
return original.getData(); // OriginalBroker1.getData():Object
}
public boolean logOff(Map<String,Object> options) {
return original.doLogout((boolean) options.get("clearSession"));
}
public boolean logoff() {
HashMap<String,Object> options = new HashMap<String,Object>();
options.put("clearSession", true);
return logoff(options); // proxy to original method
}
}
Or
class Broker2 extends BrokerAbstract<Integer> {
private OriginalBroker2 original;
public boolean login(String user, String pass, Map<String,Object> options) {
int code = original.doLogin(user, pass, (String) options.get("sessionId"));
if (0 != code) {
setError(code, "Custom error message"); // could use enum here for messages...
return false;
} else {
return true;
}
}
public boolean login(String user, String pass, String sessionId) {
HashMap<String,Object> options = new HashMap<String,Object>();
options.put("sessionId", sessionId);
return login(user, pass, options);
}
public int getStatus(Map<String,Object> options) { /*...*/ return 0; }
public boolean sendRequest(Map<String,Object> options) { /*...*/ return true; }
public Integer getData(Map<String,Object> options) {
return original.getData(options.get("key")); // OriginalBroker2.getData(key:String):int
}
public boolean logOff(Map<String,Object> options) {
return original.doLogout();
}
public boolean logoff() {
return logoff(null); // ignore third parameter
}
}
Of course this is a very general approach. If you know that one method will be receiving strings for all parameters, you could also have a abstract signature like :
abstract public boolean login(String...args);
Then your concrete implementation would be :
abstract class A {
abstract public boolean login(String...args);
}
class B extends A {
public boolean login(String...args) { return this.login(args[0], args[1]); }
public boolean login(String user, String pass) { return original.login(user,pass); }
}
class C {
public void login() {
B b = new B();
b.login("foo", "secret");
// or
b.login(new String[] {"foo", "secret"});
// or !
b.login("foo", "secret", "sessionId"); // will ignore third, but otherwise would still work...
}
}
etc.
My first thought was looking into the facade pattern, which, in my 'Head First Design Patterns' book, is explained in the same chapter as Adapter and compared with a remoted control for home theatre components.
This facade would sit between the client app and the various brokers. So the client wouldn't have to care, which and how many brokers are part of the 'theatre', it just have to 'press the login button' and 'all broker connections are switched on'.