I'm currently making an easy webshop application. The webshop is required to add three kinds of objects to the shoping cart. A CD, a Book or a Game. I made a class for every object which all have a toString() method.
Now I have to make a method add(..) which needs to add the specified object to an ArrayList called shoppingcart. This method needs to be called within the class Webshop which in itself has the objects that are created.
I know how to do this with multiple add methods but it's required to do it with a single method.
You will probably want to create a new type called something like AbstractItem and all your other types extend from this. It is also a good practice to hide this abstract class behind an interface. So, the AbstraxtItem class could implement an Item interface that would define the public APIs.
The AbstractItem class would define some abstract methods that its subtypes should implement like getPrice() and possibly other concrete methods that would be the common behavior for all subclasses. The shopping cart will be an ArrayList<Item> and that would be populated by the add(Item) method.
Each object in your shop which can be add should implement an interface IProduct.
You then have a list of IProduct, which you can add.
ArrayList<IProduct> shoppingBasket = new ArrayList<IProduct>();
You could let the classes CD, Book and Game implement an Interface, e.g. ShopObject.
Then you can have your shoppinCart like this:
ArrayList<ShopObject> shoppingCart = new ArrayList<ShopObject>();
OOP can help you solve this problem :
If you find CD, Book or Game has some common attribute then you can use a Base class with common features and let all these extend that class.
So CD, Book and Game extends a class say Product and you provide a generic add method which takes Product as parameter.
add(Product product);
If CD, Book and Game don't share any common features then also you can use OOPs feature to add all these in more simpler way; but here you need to use method overloading
add(CD cd);
add(Book book);
So will suggest, think over your application design and then take a call on either of the approaches.
You can use aggregate all objects in one using a discriminant to indicate which object is really being represented pretty much like variant records in Ada or unions in C.
You have a full example here: http://lambda-the-ultimate.org/node/2694#comment-40453
Related
I am learning software design now. I am a front-end guy so this may be a stupid question, but I really want to know the answer. Hope you could help me.
I have to design an E-commerce system. More specifically, I am designing the buying system in E-commerce. I have done some research on how to do it and found EAV. But after knowing the EAV is the anti-pattern, I don't want to use it and also I have to keep it simple for a beginner like me to understand the design.
Here is the class diagram I have designed by myself.
And of course, I don't think this design is correct. I have spent like three days doing research and thinking about how to solve the Product and ProductType problem.
I just want to have a product like an iPhone, for example, has the attributes belong to the phone, a coke has the attributes belong to the drink, etc.
How could I do this?
Please tell me how to solve this problem in a simple way, cause I am new to this. Some articles or books about software design could be appreciated too.
Thank you <3
Basically you know that all the products have (at least) a product type. And you know that a product type instance will end up being a drink, a telephone, etc. So, you first need
Product Type Abstractization
You will need to make sure that ProductType is either an interface or an abstract class or a base class. An interface is a declared entity type, whose capabilities are known, but not implemented. It is the job of the classes implementing the interface to implement its methods. An abstract class is a fully declared, but only partially defined entity type. If you have an abstract class, then you are able to implement some of its methods, but you delegate the implementation of some of its method to its implementing subclasses. A base class is a class which is fully defined.
So your first decision is to make ProductType one of the following:
interface
abstract class
base class
You will need to think about what the common capabilities of product types are. If they should have some methods which work exactly the same, then you do not necessarily need an interface, but you will need an abstract class or a base class. If you decide not to define an interface at this point, that's fine. Later you can define it if you realize that you need it anyway. So, assuming that the methods of the separate product types are at least partially common, you will need to have some class. By default it should be a base class, that is, a normal class which has all the methods a ProductType should have implemented. Son't worry, if some specific product types should behave in a different manner in the case of some methods in comparison to the base class, you can always override base class methods for subclasses.
However, you might need an abstract class. In order to decide whether an abstract class is the way to go is to find out whether there is at least such a method that should NOT be implemented by the base class in any circumstances, because that method is always known only on subclass-level. For example, if you have an evaluate method, then you will probably need to implement it separately for your product types, because a phone is evaluated in a different manner in comparison to car.
Next, you need to define specific ProductType subclasses, that is, classes which extends/implement ProductType. We know that a ProductType may have 0 or more Products, but can a product be of more product types?
Handling one-to-many vs. many-to-many relations
A product will need to have a ProductType if there is no possibility for more product types to be associated to a single Product. Otherwise you will need a collection of product types by product.
Abstractization of Product
Since Product is also something much more general, you will probably need to invoke Product methods from ProductType. This means that you will need to decide whether Product is an:
interface
abstract class
base class
as well, with a similar thought process as the one you have used when decided what ProductType should be.
ProductType and Product trees
It's a big question whether there can be subtypes, sub-subtypes, etc. for ProductType and Product. If that's the case, you will need to implement trees for them with proper insert/update/delete/search functionalities, as you need them
Use your abstractizations
Whenever possible, do not refer to specific product types, because then you will have to copy-paste that code for other products and product types. Whenever the same pattern is true for all your product types or products, refer them by their most abstract representation (their interface, abstract class or base class, respectively) and only use concrete types at instantiation and when you are forced to.
Factories
Use factory methods for instantiation instead of constructors, because a factory method can return the instance of a subtype if that's what you need.
Given the following code:
class Vehicle{
public void operate(){
System.out.println("The vehicle is being operated.");
}
}
class Car extends Vehicle{
public void operate(){
System.out.println("The car is being operated.");
}
}
public class Simulation{
public static void main(String[] args){
Vehicle vehicle1 = new Car();
Vehicle vehicle2 = new Vehicle();
vehicle1.operate();
vehicle2.operate();
}
}
What is the benefit of declaring vehicle1 as a Vehicle when we end up initializing it as Car? Shouldn't we just declare it as a Car?
In this example it's not obvious to see the benefit. However, doing so has these benefits:
Usually you'll be calling methods with your object. So we have two options ...myFunction(Vehicle vehicle) or myFunction(Car car). If you choose to use Car, you are restricting the type that can be passed to that method. This is very important. Keep in mind software changes a lot, requirements change, enhancements are made. Let's suppose now you have a shiny new object a Ferrari which extends Vehicle, you cannot call myFunction(Car car) but you will be able to call myFunction(Vehicle vehicle) by passing Ferrari. So in order to make your call using myFunction you will have to change the function signature. Sometimes you cannot change the function signature because, well, it is a library and you don't have the source code. Or maybe you can change it but if you do you will break people using your code. In larger software development, teams are split and you have to create some classes that others will use to complete the whole project. Or you will create libraries and ship to clients. That's the main reason there is polymorphism: to make it easy for many teams to work together without breaking each others code and also improve on the code by using subclasses without breaking things.
When you are writing only a small piece of code that you are not going to share with anyone and don't plan on expanding that code base, there is not much of a benefit. However it is a good habit to have.
Intent: by declaring it as Vehicle, you are showing in your code that you only care about something that has the behavior of a Vehicle .i.e you can call operate(). When you extend a class you can add additional behaviors/methods to it. By declaring it as Vehicle you won't be able to call any of new methods in Car. Remember that your code will most likely be read by others (if it's not your sole property), so using Vehicle makes it obvious that you only care about something that can operate().
Collections: Very often you need to create objects and use them as a collection. Let's imagine you have a race of Vehicles. To make all the Vehicles start, you can easily use Vehicle[] and stuff all of them in there if you use Vehicle. If you were using the Car, Ferrari, Van... you could only stuff them if you use Object[] and then you will have to cast to ((Vehicle)arrayElement).operate() instead of just arrayElement.operate(). I'm giving a simplistic example but I think you'll get the idea.
So to conclude, from only your code there is on the surface no direct benefit but from the reasons above there will be a benefit if you use Vehicle and there is benefit to do so now because you will build good habits and think more OOP and about the bigger picture.
Declaring it locally in a method like that there isn't much difference. Generally speaking you get more flexibility by working on references of the most abstract type that can possibly work. You might see that in code like List<String> foo = new ArrayList<>(); because List is enough.
For example look at Collections.sort(). It takes a List because list elements are ordered. It can't just take Collection because collections aren't guaranteed to be ordered, like Set. But it can use any implementation of List, like ArrayList, LinkedList, etc because ordering is the only property sort() cares about.
I'm creating an application where I use genetic algorithm (not implemented yet) to make creatures follow food and avoid obstacles.
I have in my simulation class (where the magic happens) an arraylist where all the creatures are stored. To be noted the arraylist is full of abstract class objects whereas my creatures are all a subclass of Creature.
My question is: how can I make another ArrayList or similar where i can iterate over the arraylist and extract a particular subclass? I had a look and it seems there is no way for me to do so because of how java Collections work. Is there any kind of workaround or some library that could make this possible for me?
It is important for me to have separate lists because I need to apply behaviours to different kind of creature and weigh them according to the "dna" of the creature.
GitHub repository for the whole project: https://github.com/Jamesinvi/Animosity/tree/master/Animosity
I tried this but I get a list of all creatures because they are all of the Creature class
//in PSEUDOCODE i would like to do this:
new ArrayList newlist=new ArrayList<Creature>();
for(Creature old:oldList){
if (old instanceof CreatureSubclass){
newlist.add(old);
}
}
Disclaimer: I am a student so forgive me if this is kind of a stupid question but I am struggling a bit with this. Thanks for the help :)
ArrayList <Creature>oldlist=new ArrayList<Creature>();
ArrayList <Creature>newlist=new ArrayList<Creature>();
for(int i=0;i<oldlist.size();i++){
if (oldlist.get(i) instanceof CreatureSubclass){
newlist.add(oldlist.get(i));
}
}
Totally agree with OldCurmudgeon. You should not extract the subclass.
If you really want to do that, one ugly method is to add a string as a member variable to Creature class called flag. So you could use the string comparison instead of instance of which is very dangerous.
if (oldCreature.flag.equals("SmallCreature"))
{
newList.add(oldCreature); // another possible error: do you need a new copy or just reference?
}
And you could consider use enum class instead of string, which would also be a feasible and simple solution.
public enum CreatureName{SmallCreature, LargeCreature}
And again if you want to apply different behaviors onto the different kinds of the subclass (dna), do you have ever considered the design patterns like strategy or abstract class? The visitor pattern may be a good one mentioned by JB Nizet. But it may be overkill for this question.
If we have a parent class Vehicle and its child classes as Bus, BiCycle, MotorBike.
At a certain point of time in a service class, I will be getting all the objects like List vehicles.
My Business logic should be like below,
A list of faulty vehicles will be received and for each vehicle type, a respective mechanic should be allocated.
If I receive a bicycle it should go to a bicycle mechanic or other vehicle and their respective mechanics.
It looked bad when I used to switch case and if else conditions.So I tried to use the Visitor pattern and Factory pattern, Factory pattern also will use either switch or if-else conditions to get the object dynamically and call the overridden method. Currently using the visitor pattern.
Kindly suggest some approach which would work better with this case.
Define a sendToMechanic abstract method in Vehicle class and override it with the appropriate definition in each of the child classes.
I would suggest all three subclasses to implement the same interface (e.g. repairable) with a method like `allocateToMechanic. An interface is mostly describing "what an object can do" vs the abstract class which describes "what an object is".
I know that in Java most people declare a list using:
List l = new ArrayList();
But what would be the difference between that and
AbstractList l = new ArrayList();
What are the advantages of using an interface over an abstract class in this particular instance?
Original answer:
An abstract class allows you to define some shared functionality, while leaving other functionality to be defined by implementations. Thus, abstract classes are useful if you are going to create a family of similar classes that share some functionality but have customizations.
An interface doesn't allow you to define any functionality. It simply defines a set of method signatures that you know can be called on any object of a class that implements that interface.
I'd say the accepted practice is not to use an abstract class to fill the role of an interface. That is, an abstract class should be used for code sharing among related classes that you define, whereas an interface should be used for abstraction.
One reason not to use abstract classes to fill the role of interfaces is that a class cannot inherit from more than one class, but it can implement many interfaces. Thus, using abstract classes limits your design a lot more than using interfaces does.
Edit:
In this particular instance, the difference would be that if you later reassigned l to contain an object that implements List but does not derive from AbstractList, your code will throw an exception. Not all classes that implement List also extend AbstractList.
Using AbstractList limits you to only working with lists that are derived from the core AbstractList functionality. On the other hand, anyone could write a class that implements List using totally new code, and if you're using a variable of type List then you'll still be compatible with their new class that you've never seen before.
The fact that Java's lists are derived from AbstractList should be treated as an implementation detail that's internal to the Java library, not as an interface that you should code against.
The hierarchy is like...
ArrayList extends AbstractList implements List
and
AbstractList implements List
So,
whenever you are creating a object of ArrayList like given below, You will be creating object of ArrayList with reference of List
List list = new ArrayList();
Another thing to note is, why it is required to implement List in both class,
So,
it is for the purpose of showing that ArrayList implements List.
AbstractList in the whole picture is just for convenience and to
reduce code duplication between List implementations.
Reference: This SO Answer
In this case it wouldn't be really different. However it's a common code style to use the interface as the variable type, as the abstract implementation of AbstractWhatever class is mean to make it easier to create an implementation without having to implement all of the methods in the interface.
So it's a style issue, not really a technical one.