Call multiple classes without switch-case or if-else - switch-statement

I want to know weather is is possible or not, a way to call different classes on the basis of an integer value without conditional statements like switch case?
What I am having is:
int val = // getting some value here from a method
String data = // getting some value here from a method
switch(val)
{
case 1:
{
new TempClass1(data);
break;
}
case 2:
{
new TempClass2(data);
break;
}
}
What I want is like:
int val = // getting some value here from a method
String data = // getting some value here from a method
new TempClass(val, data);
This should call the object of TempClass1 or TempClass1 as per "val"
Any help will be appreciated.

Maybe use a Factory for the classes, assuming your two classes share a base class named TempBaseClass:
class TempClassFactory {
static public TempBaseClass getTempClass(int val, String data)
{
switch(val)
{
case 1:
{
return new TempClass1(data);
break;
}
case 2:
{
return new TempClass2(data);
break;
}
default:
throw new Exception("Bad value");
}
}
}
int val = // getting some value here from a method
String data = // getting some value here from a method
TempClassFactory::getTempClass(val, data);

Related

Generic Template String like in Python in Dart

In python, I often use strings as templates, e.g.
templateUrl = '{host}/api/v3/{container}/{resourceid}'
params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
api.get(templateUrl.format(**params))
This allows for easy base class setup and the like. How can I do the same in dart?
I'm assuming I will need to create a utility function to parse the template and substitute manually but really hoping there is something ready to use.
Perhaps a TemplateString class with a format method that takes a Map of name/value pairs to substitute into the string.
Note: the objective is to have a generic "format" or "interpolation" function that doesn't need to know in advance what tags or names will exist in the template.
Further clarification: the templates themselves are not resolved when they are set up. Specifically, the template is defined in one place in the code and then used in many other places.
Dart does not have a generic template string functionality that would allow you to insert values into your template at runtime.
Dart only allows you to interpolate strings with variables using the $ syntax in strings, e.g. var string = '$domain/api/v3/${actions.get}'. You would need to have all the variables defined in your code beforehand.
However, you can easily create your own implementation.
Implementation
You pretty much explained how to do it in your question yourself: you pass a map and use it to have generic access to the parameters using the [] operator.
To convert the template string into something that is easy to access, I would simply create another List containing fixed components, like /api/v3/ and another Map that holds generic components with their name and their position in the template string.
class TemplateString {
final List<String> fixedComponents;
final Map<int, String> genericComponents;
int totalComponents;
TemplateString(String template)
: fixedComponents = <String>[],
genericComponents = <int, String>{},
totalComponents = 0 {
final List<String> components = template.split('{');
for (String component in components) {
if (component == '') continue; // If the template starts with "{", skip the first element.
final split = component.split('}');
if (split.length != 1) {
// The condition allows for template strings without parameters.
genericComponents[totalComponents] = split.first;
totalComponents++;
}
if (split.last != '') {
fixedComponents.add(split.last);
totalComponents++;
}
}
}
String format(Map<String, dynamic> params) {
String result = '';
int fixedComponent = 0;
for (int i = 0; i < totalComponents; i++) {
if (genericComponents.containsKey(i)) {
result += '${params[genericComponents[i]]}';
continue;
}
result += fixedComponents[fixedComponent++];
}
return result;
}
}
Here would be an example usage, I hope that the result is what you expected:
main() {
final templateUrl = TemplateString('{host}/api/v3/{container}/{resourceid}');
final params = <String, dynamic>{'host': 'www.api.com', 'container': 'books', 'resourceid': 10};
print(templateUrl.format(params)); // www.api.com/api/v3/books/10
}
Here it is as a Gist.
Here is my solution:
extension StringFormating on String {
String format(List<String> values) {
int index = 0;
return replaceAllMapped(new RegExp(r'{.*?}'), (_) {
final value = values[index];
index++;
return value;
});
}
String formatWithMap(Map<String, String> mappedValues) {
return replaceAllMapped(new RegExp(r'{(.*?)}'), (match) {
final mapped = mappedValues[match[1]];
if (mapped == null)
throw ArgumentError(
'$mappedValues does not contain the key "${match[1]}"');
return mapped;
});
}
}
This gives you a very similar functionality to what python offers:
"Test {} with {}!".format(["it", "foo"]);
"Test {a} with {b}!".formatWithMap({"a": "it", "b": "foo"})
both return "Test it with foo!"
It's even more easy in Dart. Sample code below :
String host = "www.api.com"
String container = "books"
int resourceId = 10
String templateUrl = "$host/api/v3/$container/${resourceId.toString()}"
With the map, you can do as follows :
Map<String, String> params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
String templateUrl = "${params['host']}/api/v3/${params['container']}/${params['resourceId']}"
Note : The above code defines Map as <String, String>. You might want <String, Dynamic> (and use .toString())
Wouldn't it be simplest to just make it a function with named arguments? You could add some input validation if you wanted to.
String templateUrl({String host = "", String container = "", int resourceid = 0 }) {
return "$host/api/v3/$container/$resourceId";
}
void main() {
api.get(templateUrl(host:"www.api.com", container:"books", resourceid:10));
}

Trying to compute a method to call in a Bean

I have a managed bean that returns a number of different properties that describe an application. So it can be called to return the FilePath of a database by calling
appProps[sessionScope.ssApplication].helpFilePath
or
appProps[sessionScope.ssApplication].ruleFilePath
I'm trying to work out a generalized case where I need to call for the file path based on a value in a compositeData variable which can take on any one of 4 different values help/rule/app/main.
I wrote this SSJS and it works but I am wondering if there is a better way to make it work:
var target:String = compositeData.DBSource;
switch (target){
case "app" :
return appProps[sessionScope.ssApplication].appFilePath;
break;
case "help" :
return appProps[sessionScope.ssApplication].helpFilePath;
break;
case "rule" :
return appProps[sessionScope.ssApplication].ruleFilePath;
break;
case "main" :
return appProps[sessionScope.ssApplication].mainFilePath;
break;
}
I can't figure out if there is a way to compute the method by using compositeData.DBSource + "FilePath" . when I try this I get an error that the method does not exist. Using the SSJS code above is not really a problem but it just seems a bit redundant.
You can make a new method in your managed bean that takes target as an argument:
public String getFilePath(String target) {
String returnValue = "";
if (target.equalsIgnoreCase("app")) {
returnValue = this.appFilePath;
} else if (target.equalsIgnoreCase("help")) {
returnValue = this.helpFilePath;
} else if (target.equalsIgnoreCase("rule")) {
returnValue = this.ruleFilePath;
} else if (target.equalsIgnoreCase("main")) {
returnValue = this.mainFilePath;
}
return returnValue;
}
And then call it like this in your SSJS:
appProps[sessionScope.ssApplication].getFilePath(compositeData.DBSource);

j2me - Filter results by two or more criteria

I'm trying to filter some records using the RecordFilter interface. In my app I have a couple of interfaces similar to this one, on which the user can enter an ID or Name (he/she could enter both or neither of them too)
Here's what I've done so far:
The Customer filter.
Here if the user didn't enter an ID, I pass 0 as a default value, that's why I evaluate customerID!=0
public class CustomerFilter implements RecordFilter {
private String mName_Filter;
private int mID_Filter;
public CustomerFilter(String name_Filter, int id_Filter) {
this.mName_Filter = name_Filter.toLowerCase();
this.mID_Filter = id_Filter;
}
public boolean matches(byte[] candidate) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(candidate);
DataInputStream dis = new DataInputStream(bis);
int customerID = dis.readInt();
String customerName = dis.readUTF().toLowerCase();
if ((customerName != null && customerName.indexOf(mName_Filter) != -1) && (customerID != 0 && customerID == mID_Filter))
return true;
if (customerName != null && customerName.indexOf(mName_Filter) != -1 && customerID == 0)
return true;
if (customerName == null && (customerID != 0 && customerID == mID_Filter))
return true;
if (customerName == null && customerID == 0)
return true;
} catch (IOException ex) {
//What's the point in catching a exception here???
}
return false;
}
}
The search method:
Note: This method is in a class that I call "RMSCustomer", in which I deal with everything related to RMS access. The search method receives two parameters (id and name) and uses them to instantiate the filter.
public Customer[] search(int id, String name) throws RecordStoreException, IOException {
RecordStore rs = null;
RecordEnumeration recEnum = null;
Customer[] customerList = null;
try {
rs = RecordStore.openRecordStore(mRecordStoreName, true);
if (rs.getNumRecords() > 0) {
CustomerFilter filter = new CustomerFilter(name, id);
try {
recEnum = rs.enumerateRecords(filter, null, false);
if (recEnum.numRecords() > 0) {
customerList = new Customer[recEnum.numRecords()];
int counter = 0;
while (recEnum.hasNextElement()) {
Customer cust;
int idRecord = recEnum.nextRecordId();
byte[] filterRecord = rs.getRecord(idRecord);
cust = parseRecord(filterRecord);
cust.idRecord = idRecord;
customerList[counter] = cust;
counter++;
}
}
else{
customerList = new Customer[0];
//How to send a message to the midlet from here
//saying something like "No Record Exists.Please select another filter"
}
} finally {
recEnum.destroy();
}
}
else{
//How to send a message to the midlet from here
//saying something like "No Record Exists.Please Add record"
}
} finally {
rs.closeRecordStore();
}
return customerList;
}
Even though, the code shown above works I still have some questions/problems:
In the Filter :
1) How can I improve the code that evaluates the possible values of the filters (name,id)? What if I had more filters?? Will I have to test all the possible combinations??
2) If the user doesn’t enter neither a ID nor a name, should I display all the records or should I display a message "Please enter a name or ID"?? What would you do in this case?
3) Why do I have to put a try-catch in the filter when I can't do anything there?? I can't show any alert from there or can I?
In the search method:
1) How can I show a proper message to the user from that method? something like "No records" (see the "ELSE" parts in my code
Sorry If I asked too many questions, it's just that there's any complete example of filters.
Thanks in advance
How can I improve the code that evaluates the possible values of the
filters (name,id)?
The ID is the first field in the record and the fastest one to search for. If the Id matches, It doesn't really matter what the customer name is. Normally you'll be looking for the records where the ID matches OR the customer name matches, so once the ID matches you can return true. This is my proposal for the CustomerFilter class:
public class CustomerFilter implements RecordFilter {
private String mName_Filter;
//Use Integer instead of int.
//This way we can use null instead of zero if the user didn't type an ID.
//This allows us to store IDs with values like 0, -1, etc.
//It is a bit less memory efficient,
//but you are not creating hundreds of filters, are you? (If you are, don't).
private Integer mID_Filter;
public CustomerFilter(String name_Filter, Integer id_Filter) {
this.mName_Filter = normalizeString(mName_Filter);
this.mID_Filter = id_Filter;
}
//You should move this function to an StringUtils class and make it public.
//Other filters might need it in the future.
private static String normalizeString(final String s){
if(s != null){
//Warning: you might want to replace accentuated chars as well.
return s.toLowerCase();
}
return null;
}
public boolean matches(byte[] candidate) {
ByteArrayInputStream bis = new ByteArrayInputStream(candidate);
DataInputStream dis = new DataInputStream(bis);
try {
if(mID_Filter != null){
//If the ID is unique, and the search is ID OR other fields, this is fine
int customerID = dis.readInt();
if(mID_Filter.intValue == customerID){
return true;
} else {
return false;
}
}
if(mName_Filter != null){
String customerName = normalizeString(dis.readUTF());
if(customerName != null && customerName.indexOf(mName_Filter) != -1){
return true;
}
}
if(mID_Filter == null && mName_Filter == null){
return true; // No filtering, every record matches.
}
} catch (IOException ex) {
//Never swallow exceptions.
//Even if you are using an underlying ByteArrayInputStream, an exception
//can still be thrown when reading from DataInputStream if you try to read
//fields that do not exists.
//But even if no exceptions were ever thrown, never swallow exceptions :)
System.err.println(ex);
//Optional: throw ex;
} finally {
//Always close streams.
if(bis != null){
try {
bis.close();
} catch(IOException ioe){
System.err.println(ioe);
}
}
if(dis != null){
try {
dis.close();
} catch(IOException ioe){
System.err.println(ioe);
}
}
}
return false;
}
}
What if I had more filters?? Will I have to test all the possible
combinations??
It depends on your project. Usually the ID is unique and no two records exist with the same id. In this case you should explicitly design the screen so that the user understands that either he types an Id, or else he fills in the other fields. The condition would be like this:
idMatches OR (field1Matches AND field2Matches AND ... fieldNMatches)
If the user types nothing, then all records will be returned.
But then again this is more a UX issue, I don't know if it is valid for your requirements.
From the programming point of view, what is clear is that the more fields you add, the more messy your filter will became. To prevent this, you could use patterns like Decorator, Composite, and even Chain of responsibility. You'll probably have to trade good design for performance though.
If the user doesn’t enter neither a ID nor a name, should I display
all the records or should I display a message "Please enter a name or
ID"?? What would you do in this case?
It depends. Is there any other way to view all records? If so, then show the message.
Why do I have to put a try-catch in the filter when I can't do
anything there?? I can't show any alert from there or can I?
You shouldn't. This class is only responsible of filtering, not of interacting with the user. You can still log the error from the catch clause, and then throw the exception again. That will propagate the exception up to RMSCustomer.search, so whatever client code is calling that function will handle the exception in the same way you are handling the other ones thrown by that method. But keep the finally clause to close the streams.
How can I show a proper message to the user from that method?
something like "No records" (see the "ELSE" parts in my code)
You shouldn't do anything related to the GUI (like showing dialogs) from the RMSCustomer class. Even if you are not using the Model-View-Controller pattern, you still want to keep your class focused on a single responsibility (managing records). This is called the Single responsibility principle.
Keeping your class isolated from the GUI will allow you to test it and reuse it in environments without GUI.
The no records case should be handled by the screen when there are zero results. An array of lenght == 0 is fine here, and the screen will show the "No results" message. For other kinds of errors, you can extend the Exception class and throw your own custom exceptions, i.e: RecordParsingException, from the RMSCustomer.search method. The screen class will then map the different exceptions to the error message in the language of the user.

entity-framework 5 initialize not null properties on createObject

I'm getting a problem when creating an instance of an entity in entity framework 5.
I'm creating it by reflection:
var method = this.objectContextinstance().GetType().GetMethod("CreateObject");
method = method.MakeGenericMethod(Type.GetType("PERSON"));
var entity = method.Invoke(this.objectContextinstance(), null);
the problem is that the not null properties are being initialized with zero, and i don't want it to.
The reason is that if i save it, it makes a reference to another object that key is zero creating wrong data.
is there a way of creating an instance and it not automatically set the non null properties or is there a configuration to set the not null properties to a value like '-1'?
The problem i mention happens creating a instance of some entity by the "new" clause.
I'm using DataBase First approach.
Any help would be appreciated! Thanks in advance!
To solve this problem, I set all of the properties to a default value after creation:
public void InitializeCreatedEntity(object entity)
{
Type tipoObj = entity.GetType();
string nomeEntidade = GetNomeEntidade(entity);
foreach (EntityType entityType in EntityTypes)
{
if (entityType.Name.Equals(nomeEntidade))
{
foreach (EdmProperty property in entityType.Properties)
{
if (!property.Nullable)
{
PropertyInfo info = tipoObj.GetProperty(property.Name);
switch (property.TypeUsage.EdmType.Name)
{
case "String": info.SetValue(entity, "", null);
break;
case "Int32": info.SetValue(entity, DefaultInt, null);
break;
case "Int64": info.SetValue(entity, DefaultInt, null);
break;
case "Int16": info.SetValue(entity, DefaultInt, null);
break;
case "Binary": Byte[] initByteArray = { };
info.SetValue(entity, initByteArray, null);
break;
case "DateTime": info.SetValue(entity, DateTime.Now, null);
break;
}
}
}
}
}
}

Casting on run time using implicit con version

I have the following code which copies property values from one object to another objects by matching their property names:
public static void CopyProperties(object source, object target,bool caseSenstive=true)
{
PropertyInfo[] targetProperties = target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
PropertyInfo[] sourceProperties = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo tp in targetProperties)
{
var sourceProperty = sourceProperties.FirstOrDefault(p => p.Name == tp.Name);
if (sourceProperty == null && !caseSenstive)
{
sourceProperty = sourceProperties.FirstOrDefault(p => p.Name.ToUpper() == tp.Name.ToUpper());
}
// If source doesn't have this property, go for next one.
if(sourceProperty ==null)
{
continue;
}
// If target property is not writable then we can not set it;
// If source property is not readable then cannot check it's value
if (!tp.CanWrite || !sourceProperty.CanRead)
{
continue;
}
MethodInfo mget = sourceProperty.GetGetMethod(false);
MethodInfo mset = tp.GetSetMethod(false);
// Get and set methods have to be public
if (mget == null)
{
continue;
}
if (mset == null)
{
continue;
}
var sourcevalue = sourceProperty.GetValue(source, null);
tp.SetValue(target, sourcevalue, null);
}
}
This is working well when the type of properties on target and source are the same. But when there is a need for casting, the code doesn't work.
For example, I have the following object:
class MyDateTime
{
public static implicit operator DateTime?(MyDateTime myDateTime)
{
return myDateTime.DateTime;
}
public static implicit operator DateTime(MyDateTime myDateTime)
{
if (myDateTime.DateTime.HasValue)
{
return myDateTime.DateTime.Value;
}
else
{
return System.DateTime.MinValue;
}
}
public static implicit operator MyDateTime(DateTime? dateTime)
{
return FromDateTime(dateTime);
}
public static implicit operator MyDateTime(DateTime dateTime)
{
return FromDateTime(dateTime);
}
}
If I do the following, the implicit cast is called and everything works well:
MyDateTime x= DateTime.Now;
But when I have a two objects that one of them has a DateTime and the other has MyDateTime, and I am using the above code to copy properties from one object to other, it doesn't and generate an error saying that DateTime can not converted to MyTimeDate.
How can I fix this problem?
One ghastly approach which should work is to mix dynamic and reflection:
private static T ConvertValue<T>(dynamic value)
{
return value; // This will perform conversion automatically
}
Then:
var sourceValue = sourceProperty.GetValue(source, null);
if (sourceProperty.PropertyType != tp.PropertyType)
{
var method = typeof(PropertyCopier).GetMethod("ConvertValue",
BindingFlags.Static | BindingFlags.NonPublic);
method = method.MakeGenericMethod(new[] { tp.PropertyType };
sourceValue = method.Invoke(null, new[] { sourceValue });
}
tp.SetValue(target, sourceValue, null);
We need to use reflection to invoke the generic method with the right type argument, but dynamic typing will use the right conversion operator for you.
Oh, and one final request: please don't include my name anywhere near this code, whether it's in comments, commit logs. Aargh.

Resources