Object-oriented programming organizes design around object-oriented languages, concepts, patterns, and ideas. Its practical aim is to divide a large application into understandable parts, reducing the accidental complexity that makes software risky and expensive to maintain. It is imperative under the hood, but serves as a reasoning framework for turning requirements and domain models into high-level code structures. section 1.4 section 1.4.2 section 1.6
Objects and interfaces can isolate awkward dependencies behind a fitting contract. Rather than letting application code depend directly on a thermometer that reports Kelvin, an adapter can expose the Celsius-based sensor interface the application requires. This localizes conversion and protects the rest of the design from a mismatched API. section 1.4.2
Listing 1.5 Adapter pattern
final class HighAccuracyThermometer { #1
def name() : String = "HAT-53-2"
def getKelvin() : Float = {
native.core.highAccuracyThermometer.getData()
}
}
final class HAThermometerAdapter ( #2
thermometer: HighAccuracyThermometer)
extends ISensor {
val t = thermometer #3
def getData() : Float = { #4
val data = t.getKelvin()
native.core.utils.toCelsius(data)
}
def getName() : String = t.name()
def getDataType() : String = "temperature"
}
The adapter example shows an object wrapping a high-accuracy thermometer, converting Kelvin to Celsius, and implementing the required sensor interface. section 1.4.2
Object-oriented patterns provide general, language-agnostic responses to recurring design problems. They are useful tools, not automatic answers: some structures, such as command and strategy, can require many classes, while higher-order functions, lambdas, and closures may express comparable behavior more concisely in a functional style. section 1.4.2
Maintainability and reuse depend on explicit responsibilities and dependable interfaces:
- Use contracts to state behavior that implementations must honor; otherwise behavior becomes difficult to predict. section 1.4.3
- Apply SOLID principles to reason about responsibility, interfaces, substitution, and dependencies. section 1.4.3
- Require substitutions to be transparent to client code. An implementation that throws an unexpected exception through a shared interface violates the Liskov substitution principle. section 1.4.3
- Favor low coupling and high cohesion to keep complexity manageable; these principles are not exclusive to object-oriented code. section 1.6
Lamp substitution failure
A routine can switch off a list through an ILampSwitcher interface. DaylightLamp honors that contract, but TableLamp throws an exception while switching. Replacing the interface with that implementation therefore forces client code to handle behavior it was not promised, exposing a broken substitution contract. section 1.4.3
UML can communicate object-oriented designs through class diagrams, while use-case diagrams remain implementation-paradigm agnostic. Design choices should be guided by the problem and architecture rather than by assuming that a diagram or principle belongs to only one programming paradigm. section 1.3 section 1.6








