How to couple an instance member to a instance method? - java

I have a class structure like :
public interface DBReader {
public Map<String, String> read(String primaryKey, String valueOfPrimaryKey,
boolean scanIndexForward, boolean consistentRead, int maxPageSize);
public int getA(String ___);
public int getB(String ___);
public int getC(String ___);
}
public class DynamoDBReader implements DBReader {
private DynamoDB dynamoDB;
private String tableName;
private Table table;
private int throughput;
private DynamoDBReader(Builder builder) {
this.throughput = builder.throughput;
this.tableName = builder.tableName;
this.dynamoDB = builder.dynamoDB;
this.table = dynamoDB.getTable(builder.tableName);
if (table == null) {
throw new InvalidParameterException(String.format("Table %s doesn't exist.", tableName));
}
}
#Override
public int getA(String ____) {
read(_________);
}
return ________;
}
#Override
public int getB(String ____) {
read(_________);
}
return ________;
}
#Override
public int getC(String ____) {
read(_________);
}
return ________;
}
#Override
public Map<String, String> read(String primaryKey, String valueOfPrimaryKey, boolean scanIndexForward,
boolean consistentRead, int maxPageSize) {
QuerySpec spec = new QuerySpec()
.withHashKey(primaryKey, valueOfPrimaryKey)
.withScanIndexForward(scanIndexForward)
.withConsistentRead(consistentRead)
.withMaxPageSize(maxPageSize);
ItemCollection<QueryOutcome> items = table.query(spec);
Iterator<Item> itemIterator = items.firstPage().iterator();
Map<String, String> itemValues = new HashMap<String, String>();
while (itemIterator.hasNext()) {
Item item = itemIterator.next();
}
return itemValues;
}
}
#VisibleForTesting
protected void setTable(Table table) {
this.table = table;
}
/**
* Returns a new builder.
*/
public static Builder builder() {
return new Builder();
}
public static class Builder {
private String tableName;
private int throughput;
private DynamoDB dynamoDB;
private Builder() { }
public Builder tableName(String tableName) {
this.tableName = tableName;
return this;
}
public Builder throughput(int throughput) {
this.throughput = throughput;
return this;
}
public Builder dynamoDB(DynamoDB dynamoDB) {
this.dynamoDB = dynamoDB;
return this;
}
public DynamoDBReader build() {
if (tableName == null) {
throw new InvalidParameterException("Table name can't be null.");
}
if (throughput <= 0) {
throw new InvalidParameterException("Throughput should be > 0.");
}
if (dynamoDB == null) {
throw new InvalidParameterException("dynamoDB can't be null.");
}
return new DynamoDBReader(this);
}
}
}
Problem : getA(), getB(), getC() are only valid for specific tableNames. For a table getA() is Valid but getB() and getC() wont make any sense.
How to couple method names with table name so that someone with a table name knows which function is valid.
Solution to create subclasses for different getters doesn't look a great idea to me.

Solution to create subclasses for different getters doesn't look a great idea to me.
Can you please elaborate why?
I hear that all the time, 'I don't like it...', 'This seems ugly...', 'It shouldn't do that'. Reasons for not liking a particular solution should be backed by objective reasons, not personal opinions. Most of the time our intuition as developers tells us that something is wrong when it is actually violating some software development principle. But sometimes it is just plain old personal feeling without any particular logical reason. When that happens I like to get to specifics.
Your solution violates a basic software principle called SRP.
Having table modules will be much better solution.

Related

How do I make Hibernate custom types apply to aggregate functions?

We're updating a Hibernate (3.6) application that defines a custom type for money, extending org.hibernate.type.ImmutableType. It's been fairly straightforward to make it instead extend AbstractSingleColumnStandardBasicType and create a Java type descriptor to store Money as BigInteger.
However, various parts of the application use HQL queries that perform aggregate functions (usually SUM) on money fields. The old style, extending ImmutableType, automatically converted the result to Money, but with the new style, that's not happening; the result is a Long.
Does anyone know how to make Hibernate custom types automatically convert the result of aggregate functions?
Old user type:
public class MoneyUserType extends ImmutableType {
private final BigIntegerType bigIntegerType = new BigIntegerType();
#Override
public Object fromStringValue(final String string) {
final BigInteger bigInteger = (BigInteger) bigIntegerType.fromStringValue(string);
return Money.inCents(bigInteger);
}
#Override
public Object get(final ResultSet rs, final String name) throws SQLException {
final BigInteger bigInteger = (BigInteger) bigIntegerType.get(rs, name);
if (null == bigInteger) {
return null;
}
return Money.inCents(bigInteger);
}
#Override
public void set(final PreparedStatement st, final Object object, final int index) throws SQLException {
final Money money = (Money) object;
bigIntegerType.set(st, money.getAmountInCents(), index);
}
#Override
public int sqlType() {
return bigIntegerType.sqlType();
}
#Override
public String toString(final Object object) {
final Money money = (Money) object;
return bigIntegerType.toString(money.getAmountInCents());
}
public String getName() {
return Money.class.getName();
}
#SuppressWarnings("unchecked")
public Class getReturnedClass() {
return Money.class;
}
}
New user type:
public class MoneyUserType extends AbstractSingleColumnStandardBasicType<Money> {
public MoneyUserType() {
super(BigIntTypeDescriptor.INSTANCE, MoneyJavaTypeDescriptor.INSTANCE);
}
#Override
public String getName() {
return Money.class.getName();
}
}
public class MoneyJavaTypeDescriptor extends AbstractTypeDescriptor<Money> {
public static final MoneyJavaTypeDescriptor INSTANCE = new MoneyJavaTypeDescriptor();
public MoneyJavaTypeDescriptor() {
super(Money.class, ImmutableMutabilityPlan.INSTANCE);
}
#Override
public Money fromString(final String string) {
final BigInteger bigInteger = BigIntegerTypeDescriptor.INSTANCE.fromString(string);
return Money.inCents(bigInteger);
}
#Override
public <X> X unwrap(Money value, Class<X> type, WrapperOptions options) {
if (value == null) {
return null;
}
if (type.isAssignableFrom(BigInteger.class)) {
return (X) value.getAmountInCents();
}
if (type.isAssignableFrom(Long.class)) {
return (X) Long.valueOf(value.getAmountInCents().longValue());
}
if (type.isAssignableFrom(Integer.class)) {
return (X) Integer.valueOf(value.getAmountInCents().intValue());
}
throw unknownUnwrap(type);
}
#Override
public <X> Money wrap(X value, WrapperOptions options) {
if (value == null) {
return null;
}
if (Number.class.isInstance(value)) {
return Money.inCents((Number) value);
}
throw unknownWrap(value.getClass());
}
#Override
public String toString(final Money money) {
return BigIntegerTypeDescriptor.INSTANCE.toString(money.getAmountInCents());
}
}
Looks like we can work around this by adding extra setters on our DTOs and putting aliases in the queries as per Custom type / converter in conjunction with Hibernate's Transformers.aliasToBean
It's not ideal but it can be made to work.
You can add an INSTANCE static field to your MoneyUserType:
public class MoneyUserType extends AbstractSingleColumnStandardBasicType<Money> {
public static final MoneyUserType INSTANCE = new MoneyUserType();
// ...
}
then add for example the following function to your custom hibernate dialect:
public class MyPostgreSQLDialect extends PostgreSQL10Dialect
{
public MyPostgreSQLDialect()
{
registerFunction("sum_money", new StandardSQLFunction("sum", MoneyUserType.INSTANCE));
}
}
declare this dialect in your persistence.xml or hibernate.cfg.xml
and then you will be able to use the sum_money function in your hql:
Money sum = entityManager.createQuery(
"select sum_money(m.money) from MoneyEntity m",
Money.class
).getSingleResult();

Not sure how I am supposed to keep this Arraylist from being editable

I have this class, Party, in which I have an arraylist RSVP and an arraylist invited. The goal is that One should be able to add a name to these arraylists using my addInvited() and get it using getInvited(). I know the problem is in one of these two methods, as every other method has passed its test. I need to make it so that someone can add a Person object using addInvited(), but that Person CANNOT change his name. I can't seem to figure out if I'm just not making a deep enough copy, or what...
package lab04partB;
import java.util.ArrayList;
public class Party {
private ArrayList<Person> invited;
private ArrayList<Person> RSVP;
public Party() {
invited = new ArrayList<Person>();
RSVP = new ArrayList<Person>();
}
public void addInvited(Person person) {
if (!invited.contains(person)) {
Person JohnDoe = new Person(person.getName());
invited.add(JohnDoe);
}
}
public ArrayList<Person> getInvited() {
ArrayList<Person> tempList = new ArrayList<Person>(invited);
return tempList;
}
public void addRSVP(Person person) {
if ((!RSVP.contains(person)) && (invited.contains(person))) {
Person JaneDoe = new Person(person.getName());
RSVP.add(JaneDoe);
}
}
public ArrayList<Person> getRSVP() {
ArrayList<Person> tempList = new ArrayList<Person>(RSVP);
return tempList;
}
}
Here is the test it is running against, if it helps!
#Test
public void testGetInvitedModifyNamesReturned() {
Party party = new Party();
Person a = new Person( new String( KANY_GARCIA ));
Person b = new Person( new String( LAURA_PAUSINI ));
party.addInvited( a );
party.addInvited( b );
ArrayList<Person> list = party.getInvited();
assertEquals( 2, list.size() );
for (Person p : list) {
p.setName( new String( MIGUEL_RIOS ));
}
list = party.getInvited();
assertEquals( "Incorrect result", 2, list.size() );
assertTrue ( "Incorrect result", list.contains( a ));
assertTrue ( "Incorrect result", list.contains( b ));
}
One way would be to make the name field in the Person class final but then no one can change the name of a person anywhere. Guess that is not what you want.
Alternatively you can create an inner class in Party that subclasses Person and disallows changing the name. Then when you add a person to a party you first convert the input argument to an immutable person.
class Party {
private static final class ImmutablePerson extends Person {
public ImmutablePerson(String name) {
super(name);
}
#Override
void setName(String s) {
throw new RuntimeException("Cannot change name");
// or just do nothing here
}
}
public void addInvited(Person person) {
ImmutablePerson immutable = new ImmutablePerson(person.getName());
if (!invited.contains(immutable)) {
invited.add(immutable);
}
}
}
Make Person immutable. It's actually best practice too, because people don't change data, and (as here) you can safely publish them.
There's a few ways you might be able to do this...
You could use interfaces to maintain the contractual expectations of the API, so you could setup non-mutable version of Person (with getters) and a mutable version (with setters), this would mean that your Party class could return the non-mutable types, preventing people from directly modifying the values.
This could lead to using the non-mutable instance as a wrapper for the mutable version, further preventing people from casting the results to get around this.
Something like...
public interface Person extends Comparable<Person> {
public String getName();
}
public class DefaultPerson implements Person {
private String name;
public DefaultPerson(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof Person)) {
return false;
}
final Person other = (Person) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
return true;
}
#Override
public int hashCode() {
int hash = 3;
hash = 37 * hash + Objects.hashCode(this.name);
return hash;
}
#Override
public int compareTo(Person arg0) {
return arg0.getName().compareTo(name) * -1;
}
public Character[] toCharacterArray(String s) {
if (s == null) {
return null;
}
int len = s.length();
Character[] array = new Character[len];
for (int i = 0; i < len; i++) {
array[i] = new Character(s.charAt(i));
}
return array;
}
#Override
public String toString() {
return getName();
}
}
Then your Party might look something like...
public static class Party {
private ArrayList<Person> invited;
private ArrayList<Person> RSVP;
public Party() {
invited = new ArrayList<Person>();
RSVP = new ArrayList<Person>();
}
public void addInvited(Person person) {
if (!invited.contains(person)) {
invited.add(person);
}
}
public List<Person> getInvited() {
return Collections.unmodifiableList(invited);
}
public void addRSVP(Person person) {
if ((!RSVP.contains(person)) && (invited.contains(person))) {
RSVP.add(person);
}
}
public List<Person> getRSVP() {
return Collections.unmodifiableList(RSVP);
}
}
The class know only deals with Person types, which are not mutable (okay, you could create instances of DefaultPerson and add them to your lists, which would prevent the caller from modifying the names, but that's up to you)
The class also makes use Collections.unmodifiableList which prevents the List from been modified by the caller! Bonus :)
It would then mean, doing something like...
List<Person> list = party.getInvited();
for (Person p : list) {
p.setName(new String("Whelma"));
}
would be impossible, because setName is not a method of Person!
But...
that might be beyond the scope of your assignment, instead, when you return the list of invitees, you could create new instances of the values then, for example...
public void addInvited(Person person) {
if (!invited.contains(person)) {
invited.add(person);
}
}
public ArrayList<Person> getInvited() {
ArrayList<Person> tempList = new ArrayList<>(invited.size());
for (Person p : invited) {
tempList.add(new Person(p.getName()));
}
return tempList;
}
This is less the optimal, but it would allow your code to pass the tests you have.
I should also point out, equals has a contractual relationship with hashcode, from the JavaDocs:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
Basically, what this means is, if you override equals you must also override hashcode (and visa-versa)

JavaScript chained builder with validation

In this Java class, note how use of the constructor has been disallowed and replaced with an interface driven builder that guides instantiation and does validation
public class Position implements Serializable {
private BigDecimal capital;
private BigDecimal tolerableRiskInPercentOfCapitalPerTrade;
private Direction direction;
private BigDecimal pricePerUnit;
private BigDecimal stopLossPricePerUnit;
private Position(){}
public final BigDecimal getTotalTolerableRiskPerTrade() {
return capital.multiply(tolerableRiskInPercentOfCapitalPerTrade.divide(new BigDecimal(100)));
}
public final BigDecimal getStopLossPerUnitLoss() {
if (direction.equals(Direction.LONG)){
return pricePerUnit.subtract(stopLossPricePerUnit);
} else {
return stopLossPricePerUnit.subtract(pricePerUnit);
}
}
public final BigDecimal getStopLossTotalLoss() {
return getStopLossPerUnitLoss().multiply(getUnitsToBuy());
}
public final BigDecimal getUnitsToBuy() {
BigDecimal result = getTotalTolerableRiskPerTrade().divide(getStopLossPerUnitLoss(), 0, BigDecimal.ROUND_DOWN);
if (capital.compareTo(result.multiply(pricePerUnit)) != 1){
return new BigDecimal(0);
} else {
return result;
}
}
public final BigDecimal getTotal() {
return getUnitsToBuy().multiply(pricePerUnit);
}
public static ICapital builder(){
return new Builder();
}
public interface ICapital {
ITolerableRiskInPercentOfCapitalPerTrade capital(final BigDecimal capital);
}
public interface ITolerableRiskInPercentOfCapitalPerTrade {
IDirection tolerableRiskInPercentOfCapitalPerTrade(final BigDecimal tolerableRiskInPercentOfCapitalPerTrade);
}
public interface IDirection {
IPricePerUnit direction(final Direction direction);
}
public interface IPricePerUnit {
IStopLossPricePerUnit pricePerUnit(final BigDecimal pricePerUnit);
}
public interface IStopLossPricePerUnit {
IBuild stopLossPricePerUnit(final BigDecimal stopLossPricePerUnit);
}
public interface IBuild {
Position build();
}
private static class Builder implements ICapital, ITolerableRiskInPercentOfCapitalPerTrade, IDirection, IPricePerUnit, IStopLossPricePerUnit, IBuild {
private final Position instance = new Position();
#Override
public Position build() {
return instance;
}
#Override
public ITolerableRiskInPercentOfCapitalPerTrade capital(final BigDecimal capital) {
basicValidate(capital);
instance.capital = capital;
return this;
}
#Override
public IDirection tolerableRiskInPercentOfCapitalPerTrade(final BigDecimal tolerableRiskInPercentOfCapitalPerTrade) {
basicValidate(tolerableRiskInPercentOfCapitalPerTrade);
if (tolerableRiskInPercentOfCapitalPerTrade.compareTo(new BigDecimal(100)) != -1) {
throw new IllegalArgumentException("riskInPercent must be lower than 100");
}
instance.tolerableRiskInPercentOfCapitalPerTrade = tolerableRiskInPercentOfCapitalPerTrade;
return this;
}
#Override
public IPricePerUnit direction(final Direction direction) {
if (direction==null) {
throw new IllegalArgumentException("argument can't be null");
}
instance.direction = direction;
return this;
}
#Override
public IStopLossPricePerUnit pricePerUnit(final BigDecimal pricePerUnit) {
basicValidate(pricePerUnit);
instance.pricePerUnit = pricePerUnit;
return this;
}
#Override
public IBuild stopLossPricePerUnit(final BigDecimal stopLossPricePerUnit) {
basicValidate(stopLossPricePerUnit);
if (instance.direction.equals(Direction.LONG) && instance.pricePerUnit.compareTo(stopLossPricePerUnit) != 1) {
throw new IllegalArgumentException("price must be higher than stopLossPrice");
}
if (instance.direction.equals(Direction.SHORT) && stopLossPricePerUnit.compareTo(instance.pricePerUnit) != 1) {
throw new IllegalArgumentException("stopLossPrice must be higher than price");
}
instance.stopLossPricePerUnit = stopLossPricePerUnit;
return this;
}
}
protected static void basicValidate(final BigDecimal bigDecimal) {
if (bigDecimal == null) {
throw new IllegalArgumentException("argument can't be null");
}
if (!(bigDecimal.signum() > 0)) {
throw new IllegalArgumentException("argument must have positive signum");
}
}
}
resulting in instantiation like this
Position.builder()
.capital(new BigDecimal(10000))
.tolerableRiskInPercentOfCapitalPerTrade(new BigDecimal(2))
.direction(Direction.LONG)
.pricePerUnit(new BigDecimal(25))
.stopLossPricePerUnit(new BigDecimal(24))
.build();
Trying to port code between languages isn't easy and identical functionality can't and shouldn't be expected. That said, are there any ways of emulating similar functionality in JavaScript? (vanilla or through some modules/libraries if necessary)
There are a few ways to do this.
One option is to do it almost exactly the same way: With a builder object that has methods to specify details and a build method (or similar) that you call to get the final object. The resulting call to build the object would look almost exactly the same (modulo type names and such).
Another option is to take advantage of JavaScript's object initializer syntax (aka "object literals") to have an "options" object that you pass into a constructor for the Position, like this:
function Position(options) {
if (/*...the options aren't valid...*/) {
throw new Error(/*...*/);
}
this.capital = options.capital;
// ...
}
Usage:
var p = new Position({
capital: 10000,
tolerableRiskInPercentOfCapitalPerTrade: 2,
direction: Direction.LONG,
pricePerUnit: 25,
stopLossPricePerUnit: 24
});
Inside the constructor, if you're going to use the data from options directly as properties on the new instance, you can use a function top copy them over:
function applyOptions(instance, options) {
Object.keys(options).forEach(function(key) {
instance[key] = options[key];
});
return instance;
}
Then:
function Position(options) {
if (/*...the options aren't valid...*/) {
throw new Error(/*...*/);
}
applyOptions(this, options);
}
(jQuery, if you use it, has an $.extend function that basically does this; Underscore, if you use it, has _.extend and _.extendOwn.)
But if you're going to be doing some manipulation of the options before storing them as properties on the new instance, a blind copy like that wouldn't be ideal.

Java ArrayList.contains() & add() method

So I'm having this problem with adding an element to an ArrayList
I have a class Media with 3 fields and another class Mediatheque with 1 field(which is an ArrayList).
Let's say I have:
A Mediatheque media = new Mediatheque
An equals(Media m) method in class Media < (important method)
I need to write a method add(Media m) which:
If the media.contenu does contain an element equals to the Media m I want to add, I must NOT add it and increase the nbEx field of the element contained in media.contenu
-Else I can add it using the add method provided by the ArrayList ( This doesn't seem too hard)
So I tried to write a contains(Media) method which uses the equals(Media m) method I wrote for the Media class and then use the contains method in the add method.
My question is that how am I supposed to write the add method? < (The Question)
I must write this using ArrayList, it is a school assignment
Sorry about the long code and the bad English, I'm a complete noob.
Here is my Media class:
package Ex1;
public class Media {
private final String support; // Format: Book, CD, DVD,etc...
private final String titre; // Title
private int nbEx; // Number of copy
public Media(String titre, String support){
this.titre = titre;
this.support = support;
this.nbEx = 1;
}
public Media (){
titre = "";
support = "";
nbEx = 0;
}
public boolean equals(Media m){
boolean equality = false;
if (m instanceof Media){
equality = (this.titre.equals(m.titre) && this.support.equals(m.support));
}
return equality;
}
public Media(Media m){
this.titre = m.titre;
this.support = m.support;
}
}
And here is my Mediatheque class:
import java.util.ArrayList;
import static java.lang.System.out;
public class Mediatheque {
ArrayList<Media> contenu;
public Mediatheque(){
this.contenu = new ArrayList<Media>();
}
public Mediatheque(Mediatheque m){
this.contenu = m.contenu;
}
public boolean contains(Media m){
int i = 0;
boolean contain = this.contenu.get(i).equals(m);
for(i = 0; i<this.contenu.size(); i++){
if(contain)
break;
}
return contain;
}
public int indexOf(Media m){
boolean retVal = this.contenu.get(i).equals(m);
for(Media i : contenu){
if(contain)
break;
}
return i;
}
public void add(Media m){
if(this.contains(m)){
this.contenu.get(this.contenu.indexOf(m)).setNbEx(this.contenu.get(this.contenu.indexOf(m)).getNbEx()+m.getNbEx());
}else{
this.contenu.add(m);
}
}
My question is that how am I supposed to write the add method?
Sorry about the long code and the bad English, I'm a complete noob.
Thank you!
As stated by #NeplatnyUdaj in the comment of your question, the use of a Map would greatly improve your code. Instead of recording the number of medias inside the Media object, use a HashMap<Media, Integer> to store your data in this way:
new HashMap<Media, Integer> map = new HashMap<Media,Integer>();
if ( map.containsKey(key) ) {
map.put(key, (map.get(key) + 1));
} else {
map.put(key, 1);
}
Where key is the media. (m in your code)
When one overrides the equals() method, one is also supposed to override the hashCode() method. The equals() method takes an Object parameter. Here's how your Media class should look like:
// Media.java
public class Media
{
private final String support;
private final String title;
public Media(String title, String support)
{
this.title = title;
this.support = support;
}
public Media(Media media)
{
this(media.title, media.support);
}
#Override
public int hashCode()
{
return 31 * title.hashCode() + support.hashCode();
}
#Override
public boolean equals(Object object)
{
if (object instanceof Media)
{
Media media = (Media) object;
return media.title.equals(title) &&
media.support.equals(support);
}
return false;
}
}
Then use a HashMap to map the media with its number of copies. Here's how that's done:
// MediaMap.java
import java.util.HashMap;
import java.util.Map;
public class MediaMap
{
// Media to its Number of Copies mapping.
private Map<Media, Integer> mediaMap;
public MediaMap()
{
mediaMap = new HashMap<>();
}
public void add(Media media)
{
mediaMap.put(media, mediaMap.getOrDefault(media, 0) + 1);
}
public void removeOneMedia(Media media)
{
if (mediaMap.containsKey(media))
{
mediaMap.put(media, mediaMap.get(media) - 1);
}
}
// And so on...
}
Without overriding the hashCode() method in the Media class, the hash based collections won't work as expected.
You can also have a look at MultiSet data structure, and use that instead.
If you are to use ArrayList then here's how its done:
// Media.java
public class Media
{
private final String support;
private final String title;
private int numberOfCopies;
public Media(Media media)
{
this(media.title, media.support, media.numberOfCopies);
}
public Media(String title, String support, int numberOfCopies)
{
this.title = title;
this.support = support;
this.numberOfCopies = numberOfCopies;
}
#Override
public int hashCode()
{
return 31 * title.hashCode() + support.hashCode();
}
#Override
public boolean equals(Object object)
{
if (object instanceof Media)
{
Media media = (Media) object;
return media.title.equals(title) &&
media.support.equals(support);
}
return false;
}
public int getNumberOfCopies()
{
return numberOfCopies;
}
public void setNumberOfCopies(int numberOfCopies)
{
this.numberOfCopies = numberOfCopies;
}
}
And here's a MediaList class which uses ArrayList:
// MediaList.java
import java.util.ArrayList;
public class MediaList
{
private ArrayList<Media> mediaList;
public MediaList()
{
mediaList = new ArrayList<>();
}
public void add(Media media)
{
set(media, +1);
}
public void remove(Media media)
{
set(media, -1);
}
private void set(Media media, int change)
{
if (change == 0)
{
return;
}
int indexOfMedia = mediaList.indexOf(media);
if (indexOfMedia != -1)
{
Media m = mediaList.get(indexOfMedia);
m.setNumberOfCopies(m.getNumberOfCopies() + change);
if (change < 0 && m.getNumberOfCopies() <= 0)
{
mediaList.remove(media);
}
}
else if (change > 0)
{
mediaList.add(media);
}
}
// And so on...
}
I have refactored your classes a little bit. I also implemented an add method. I assumed that you want to add media to the mediatheque if it is not already in the list. If it is in the list you want to add the nbex to the nbex that the item in the list has, right?
As the others I would advise you to use a HashMap() for counting if you don't need the number for your media objects.
Media.class
public class Media {
private final String support; // Format: Book, CD, DVD,etc...
private final String titre; // Title
private int nbEx; // Number of copy
public Media(String titre, String support){
this.titre = titre;
this.support = support;
this.nbEx = 1;
}
public Media(Media m){
this(m.titre, m.support);
}
public Media (){
this("", "");
nbEx = 0;
}
public boolean equals(Media m){
if (m instanceof Media){
return (this.titre.equals(m.titre) && this.support.equals(m.support));
}
return false;
}
}
Mediatheque.class
public class Mediatheque {
ArrayList<Media> contenu;
public Mediatheque(){
this.contenu = new ArrayList<Media>();
}
public Mediatheque(Mediatheque m){
this.contenu = m.contenu;
}
public boolean contains(Media m){
for(Media media: this.contenu) {
if(media.equals(m) {
return true;
}
}
return false;
}
public int indexOf(Media m){
if(this.contenu.contains(m) {
return this.contenu.indexOf(m);
}
return -1;
}
public void add(Media m){
if(this.contains(m)) {
Media media = this.contenu.get(this.contenu.indexOf(m));
media.setNbex(media.getNbex() + m.getNbex());
} else {
this.contenu.add(m);
}
}
}
Hope this helps.

how do I copy an object containing collections as fields

consider the below code:
public class Bid {
private double pe;
private List<ResChar> resourceList;
protected Map<Integer,Integer>scheduleOfSeller ;
public Map<Integer, Integer> getScheduleOfSeller() {
return scheduleOfSeller;
}
public void setScheduleOfSeller(Map<Integer, Integer> scheduleOfSeller) {
this.scheduleOfSeller = scheduleOfSeller;
}
private int bidId;
public int getBidId() {
return bidId;
}
public void setBidId(int bidId) {
this.bidId = bidId;
}
public double getPe() {
return pe;
}
public void setPe(double pe) {
this.pe = pe;
}
public List<ResChar> getResourceList() {
return resourceList;
}
public void setResourceList(List<ResChar> resourceList) {
this.resourceList = resourceList;
}
public Bid(int bidId,double pe, List<ResChar> resourceList){
setBidId(bidId);
setPe(pe);
setResourceList(resourceList);
this.scheduleOfSeller = new HashMap<Integer,Integer>();
}
}
I want to make a copy constructor of the bid like this :
public class BidCopy{
public Bid bid;
public BidCopy(Bid bidBuyer){
List<ResChar> resList = new LinkedList<ResChar>();
for (ResChar elt : bidBuyer.getResourceList()){
ResCharCopy eltCopy = new ResCharCopy(elt);
resList.add(eltCopy.elt);
}
this.bid = bidBuyer;
this.bid.setResourceList(resList);
}
}
The only solution that I know to make such copy is to proceed like follows :
public class BidCopy{
public Bid copy;
public BidCopy(Bid bid){
List<ResChar> resList = new LinkedList<ResChar>();
for (ResChar elt : bid.getResourceList()){
ResCharCopy eltCopy = new ResCharCopy(elt);
resList.add(eltCopy.elt);
}
this.copy = new Bid(bid.getBidId(), bid.getPe(), resList);
}
}
So I want to know if there is any other solution to make a copy of "Bid" Object more effectively ?
I would suggest making a copy constructor for your Bid object (and not a specific class for copying), a Bid is made out of its fields and not methods, like so:
public class Bid {
int ID;
String description;
Object bidStuff;
// ...as before
public Bid(Bid bid) {
this.ID = bid.ID;
this.description = bid.description;
this.bidStuff = bid.bidStuff;
}
public static void main(String[] args) {
List<Bid> original = new ArrayList<>();
// ..populate it
List<Bid> copy = new ArrayList<>(original.size());
for (Bid b : original) {
copy.add(new Bid(b));
}
}
}
You can even make the copy constructor protected or package-protected if you don't want anyone else to mess around with making multiple copies of bids.
There is not. Even though some collections have "copy constructors", these constructors will copy the elements' references, they will not create new elements for you.
You can however "optimize" the list creation itself by submitting the size of the initial list to the constructor:
List<X> newList = new LinkedList<X>(oldList.size());

Categories