This week’s post offers advantages and disadvantages of writing code from scratch versus using object oriented techniques.
When approaching a software project, the developer must determine the most appropriate method of development. This involves many choices, including what objects are relevant, the classes for those objects, and whether to code those classes from scratch, or to utilize object-oriented techniques like inheritance or composition (Deitel & Deitel, 2012, pp. 360-361).
Writing From Scratch
First, this post looks at the concept of writing from scratch, a term “which comes from 19th Century sports terminology” (Schach, 2011, p. 59). Generally speaking, as the term is used in programming today, the terms means to start with nothing. The advantages and disadvantages of writing from scratch include:
Advantage: When approaching a software project, the development process usually involves a process known as pseudocode. During this process, the developer formulates the algorithms that must be used as part of the project, focusing more on the goal to be achieved each logical step as opposed to the programming code itself (Deitel & Deitel, 2012, p. 113). Traditionally, developing code from scratch is the next step in development after pseudocode and it is perhaps the best way to ensure that the algorithm is constructed exactly as prescribed.
Code that is quickly implemented, or uniquely vital to the program, would be good candidates for writing from scratch. Consider, for example, pseudocode that merely calls for the creation of a integer counter variable. The simplest, and best, implementation is to simply write that code by scratch.
Disadvantage: While writing code from scratch may seem to be a good, and at times best, approach to coding, when writing code from scratch the developer misses out on potential time savings from utilizing object-oriented tools such as inheritance and composition. Generally, these include reduced maintenance, modeling of the real world which has already been completed, and improved reliability (Burleson, 2019).
Consider, for example, a program that used random numbers in various forms such as random integers, random decimals, random ranges of numbers, or even random collections of numbers. Programming the code to produce these variations could take substantial amounts of time. But Java has a ready solution for this need – the Class java.util.Random (Oracle, 2019), which when imported into a Class provides many useful methods to produce a variety of random objects.
Inheritance, where the class to be constructed takes on the attributes and methods of another class, is described as an ‘is-a’ relationship (Deitel & Deitel, p. 361). Through inheritance, a super-class makes available all of its attributes and methods for use in the sub-class. Because of the visibility of super-class attributes and methods, inheritance is sometimes referred to as “white-box reuse” (Gamma, Helm, Johnson, & Vlissides, 1995, p. 19).
For example, a car ‘is a’ vehicle, so the Car class could be constructed as a sub-class of the super-class Vehicle. This application is far more than imported static methods and values from another Class such as Random mentioned above. In this case, the super-class passes down all attributes and methods to the sub-class. If Vehicle is the super-class, for example, the attributes of the class might include number of wheels, type of power needed, or number of passengers. When the class Car inherits the Vehicle class, Car takes on the attributes of Vehicle but then adds attributes such as model, make, and gas mileage.
Advantage: Using inheritance, “time is saved during program development by basing new classes on existing proven and debugged high-quality software” (Deitel & Deitel, 2012, p. 360). Stephen R. Schach suggests that the time savings for program coding along with all the other benefits of inheritance, can be summarized as follows: “Underlying all these reasons is that a well-designed object, that is, an object with high cohesion and low coupling, models all of the aspects of one physical entity” (2011, p. 218). Schach goes on to explain that the power is that the vast majority of the implementation is hidden, consisting of attributes and methods at work in the super class, which is the essence of low coupling (2011, p. 218).
Using the car example, Car inherits Vehicle, suppose that Vehicle contains a method called paintVehicle(String colorCode, int paintCost). The method changes the vehicle attribute vehicleColor and addes paintCost to the attribute vehicleCost. When Car inherits Vehicle, there is no need to program a paintCar() method. The paintVehicle() method can be applied to Car objects once Car inherits Vehicle.
Disadvantage: A problem known as fragile base Class presents a risk for all implementations of inheritance (Schach, 2011, p. 219). This often arises after the software is complete, and is already in use, and is associated with changes in one or several super-class attributes or methods. Modifications to super classes, unless anticipated, will feed down to the sub-class attributes and methods. Because inheritance exposes the sub-class to details of the parent’s implementation, “it’s often said that inheritance breaks encapsulation” (Gamma, Helm, Johnson, & Vlissides, 1995, p. 19).
Continuing the Car inherits Vehicle example, consider a software project which needs to analyze the mileage of different model cars. Car inherits Vehicle, attributes and methods, and then adds attributes for the unique Car characteristics like model, make, manufacturer, etc. Suppose then, at a later date, the keepers of the Vehicle class decide to add a Boolean Vehicle attribute called isGreen which indicates whether or not the vehicle is environmentally friendly. They decide, on their own accord, that every Vehicle object where isGreen is unknown or undefined will be set to false. Because of this change in the parent class, Car will need to modify its constructor or risk that every car be assigned false for the isGreen attribute.
Composition occurs when multiple classes contribute their attributes and methods to a single class, and if the resultant class would cease to exist and if the aggregate class is deleted then so are the contributing classes (Schach, 2011, p. 575). Composition is used when a composition class can be said ‘has a’ component class attributes and methods.
Object composition provides an alternative to class inheritance (Gamma, Helm, Johnson, & Vlissides, 1995, p. 19). With inheritance functionality is made, in large part, with static methods extended from the super-class to the sub-class. Composition, on the other hand, offers functionality to the receiving class through object attributes and object methods. Using composition, no internal details of the contributing class need be known. As a result, in contrast to the white-box label for inheritance, composition is sometimes referred to as “black-box reuse” (Gamma, Helm, Johnson, & Vlissides, 1995, p. 19).
To illustrate composition, a car ‘has a’ steering wheel, so a proper use of composition would be to use a SteeringWheel class to construct a steeringWheel object for use in the Car class (Deitel & Deitel, 2012, p. 361). Of course, other classes like Engine, Wheels, Seats, etc. would contribute to the greater composition class so that, upon completion, the Car class would be comprised of objects from each of its composition classes.
Advantage: With composition, objects are accessed solely through their interface, so that exposure to the super-class is limited and encapsulation is maintained (Gamma, Helm, Johnson, & Vlissides, 1995, p. 19).
Continuing the Car illustration, we consider that the Car is composed of objects from several different classes like SteeringWheel, Engine, Seats, GasTank etc. These supporting classes have constructors and object methods which can be used for the composition of the Car class. However, the programming of the Car class carefully defines the interface, offering control of how the attributes of supporting classes impact the Car composition.
Disadvantage: With composition, objects are created from a variety of different classes for use together in the program. This leads to the requirement that objects “respect each other’s interfaces, which in turn requires carefully designed interfaces that don’t stop you from using one object with many others” (Gamma, Helm, Johnson, & Vlissides, 1995, p. 20.).
The Car illustration continues to offer a meaningful example. Consider the Car class being composed in part by the classes Engine and GasTank. Obviously, the GasTank and Engine classes produce objects which rely on one another. The relationship could prove problematic if not accounted for in special cases, like when the engine type changes from gas-fueled to electric, i.e. there is no need for a GasTank object. Not only must each class interface with the composition class Car, but once there they must be defined well to co-exist as needed.
Burleson, D. (2019, March 11). Advantages and disadvantages of object-oriented approach. Retrieved from BC Burleson Consulting: http://www.dba-oracle.com/t_object_oriented_approach.htm
Deitel, P., & Deitel, H. (2012). Java: How to Program 9th Edition. Boston: Prentice Hall.
Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1995). Design Patterns: Elements of Reusable Object-Oriented Software. Boston: Addison-Wesley.
Hayes, D. (2019, January 22). Is WordPress object-oriented? A thorough exploration. Retrieved from WPShout.Com: https://wpshout.com/is-wordpress-object-oriented/
Oracle. (2019, March 11). Class Random. Retrieved from Docs.Oracle.com: https://docs.oracle.com/javase/8/docs/api/java/util/Random.html
Paul, J. (2017, June 4). 5 Reasons to use composition over inheritance in Java and OOP. Retrieved from JavaRevisited: https://javarevisited.blogspot.com/2013/06/why-favor-composition-over-inheritance-java-oops-design.html
Schach, S. (2011). Object-Oriented and Classical Software Engineering, 8th edition. New York: McGraw Hill.