I'm having second thoughts about using vertical inheritance or composition for a simple OOP implementation. I've read a lot, but I'm still bad at making up my mind. ^^
I need to produce four different reports: Quote, Invoice, Catalogue and Brochure:
- Every report has the same Header and Footer.
- Quote and Invoice contain the same formatted table with different data.
- Brochure and Catalogue have different structures to the rest of the reports and no tables.
I'd like help on coming up with the OOP design here; I'll present my two ideas (pseudo code), but any feedback will be greatly appreciated. :)
Following inheritance
class Report
{
method Header()
{
// Print the header
}
method Footer()
{
// Print the footer
}
}
class ReportTable
{
method Table()
{
// Print the table
}
}
class Quote extends ReportTable
{
method BuildReport()
{
call Header()
call Table()
// Print some more quote stuff
call Footer()
}
}
class Invoice extends ReportTable
{
method BuildReport()
{
call Header()
call Table()
// Print some more invoice stuff
call Footer()
}
}
class Catalogue extends Report
{
method BuildReport()
{
call Header()
// Print catalogue stuff
call Footer()
}
}
class Brochure extends Report
{
method BuildReport()
{
call Header()
// Print brochure stuff
call Footer()
}
}
Following Composition for the table feature
class Report
{
method Header()
{
// Print the header
}
method Footer()
{
// Print the footer
}
}
class Table
{
method Table()
{
// Print the table
}
}
class Quote extends Report
{
property table
constructor Quote( Table table )
{
self.table = table
}
method BuildReport()
{
call Header()
call self.table.Table()
// Print some more quote stuff
call Footer()
}
}
class Invoice extends Report
{
property table
constructor Invoice( Table table )
{
self.table = table
}
method BuildReport()
{
call Header()
call self.table.Table()
// Print some more invoice stuff
call Footer()
}
}
class Catalogue extends Report
{
method BuildReport()
{
call Header()
// Print catalogue stuff
call Footer()
}
}
class Brochure extends Report
{
method BuildReport()
{
call Header()
// Print brochure stuff
call Footer()
}
}
Thanks a lot! :)
This may be a religious question. Either way should work, and it will be easy to refactor from one to another. The standard logic says to favor composition over inheritance, but go with what feels right.
Related
I am a complete beginner in terms of Kotlin and I am finding some issues while trying to test out a Ktor based application.
I have a file in my endpoints package localized at org.example.endpoints.hello
this file contains a fun Application.hello that implements an endpoint for my application.
This endpoint acts as a wrapper for another API, so inside that same file I have a
fun callOtherAPI(): ResponseContainer {
// networking stuff
return ResponseContainer(message: "some stuff")
}
This function gets called inside the Application's function routing implementation as such:
routing {
get("/hello") {
call.respond(callOtherAPI())
}
}
Now to the issue:
My test currently looks like this:
#Test
fun testHello() = testApplication {
application {
hello()
}
mockkStatic(::callOtherAPI)
every { callOtherAPI() } returns ResponseContainer("hello")
print(callOtherAPI()) // This actually returns the mocked response, which is what I want
client.get("/hello").apply {
val expected = ResponseContainer("hello")
val response = jacksonObjectMapper().readValue<ResponseContainer>(bodyAsText())
assertEquals(HttpStatusCode.OK, status)
assertEquals(expected.message, response.message) // This assert fails because the internal call to callOtherAPI() is not being mocked.
}
}
So the problem that I am facing is that while the mocked function is being mocked within the context of the test, it is not being mocked when called internally by the routing implementation.
Can someone point me to good documentation to figure this out, I've been at it for the past two hours to no avail :/
Thanks!
You can declare a parameter for the callOtherAPI function in the hello method. For the production and testing environment you will pass different functions in this case. Here is your code rewritten:
#Test
fun testHello() = testApplication {
application {
// hello(::callOtherAPI) this call will be for the production environment
hello { ResponseContainer("hello") }
}
client.get("/hello").apply {
assertEquals(HttpStatusCode.OK, status)
assertEquals("{\"message\":\"hello\"}", bodyAsText())
}
}
data class ResponseContainer(val message: String)
fun Application.hello(callOtherAPI: () -> ResponseContainer) {
install(ContentNegotiation) {
jackson()
}
routing {
get("/hello") {
call.respond(callOtherAPI())
}
}
}
fun callOtherAPI(): ResponseContainer {
// networking stuff
return ResponseContainer("some stuff")
}
I have the following setup at the moment
.classA {
&.classB {
}
&.classC {
}
// some more
}
So every class is dependent on classA. Not requirements changed and I need to have classB,c ... working outside of classA.
However, it's important that it's still connected to classA via &.
I'm looking for something like
.classA, {
... // the comma should indicate classA or nothing
}
The clean way would be
.classB {
&, &.classA {
// style here
}
}
for every class
I am looking for specialized singleton implementation, probably I might be using wrong terminology and hence looking for expert suggestion. Here is my scenario:
There is common code which can be called by ComponentA or ComponentB. I need to push telemetry data from the common code. Telemetry needs to have information that whether this common code get called by ComponentA or ComponentB.
So common code will have just this line of code:
telemetry.pushData(this._area, data);
where this._area tells the telemetry data is getting pushed for which component
I need to push telemetry data from multiple places so it would be good if object got created once and used through out the code lifetime
One option I can think of passing component context to the common code which in mind doesn't look right, hence looking for suggestion what kind of pattern one should use in this case?
This is what I am thinking
// Telemetry.ts file present in shared code
export class Telemetry extends Singleton {
public constructor() {
super();
}
public static instance(): Telemetry {
return super.instance<Telemetry>(Telemetry);
}
public publishEvent(data): void {
if (!this.area) {
throw new Error("Error: Initialize telemetry class with right area");
}
pushtelemetryData(this.area, data);
}
public area: string;
}
// Create Telemetry object from component A
Telemetry.instance().area = "ComponentA";
// Shared code will call telemetry publishEvent
Telemetry.instance().publishEvent(data);
Thanks
It's not a good pattern to use in TypeScript where you would generally inject dependencies.
If you must absolutely do it then you can do it by faking it somewhat:
namespace Telemetry {
var instance : SingletonSomething;
export function push(data: Any) : void {
if (instance == null) {
instance = new SingletonSomething();
}
instance.push(data);
}
class SingletonSomething() { ... }
}
and then you could call
Telemetry.push(data);
You can imitate the singleton pattern in typescript easily:
class Telemetry {
private static instance: Telemetry;
public static getInstance(): Telemetry {
if (Telemetry.instance == null) {
Telemetry.instance = new Telemetry();
}
return Telemetry.instance;
}
...
}
If you have your code in some sort of closure (module, namespace, etc) then you can replace the static member with:
let telemetryInstance: Telemetry;
export class Telemetry {
public static getInstance(): Telemetry {
if (telemetryInstance == null) {
telemetryInstance = new Telemetry();
}
return telemetryInstance;
}
...
}
But then you can also replace the static method with:
let telemetryInstance: Telemetry;
export function getTelemetryInstance(): Telemetry {
if (telemetryInstance == null) {
telemetryInstance = new Telemetry();
}
return telemetryInstance;
}
export class Telemetry {
...
}
At this point, in case you are using some sort of closure, you might ask yourself if you really need the class at all?
If you use this as a module:
// telemetry.ts
export interface TelemetryData {
...
}
export function pushData(data: TelemetryData): void {
...
}
Then you get exactly what you're looking for, and this is more of the "javascript way" of doing it.
Edit
In the telemetry module there's no need to know the users of it.
If the Telemetry.pushData function needs to have information about the object that called it then define an interface for it:
// telemetry.ts
export interface TelemetryData {
...
}
export interface TelemetryComponent {
name: string;
...
}
export function pushData(data: TelemetryData, component: TelemetryComponent): void {
...
}
Then in the other modules, where you use it:
// someModule.ts
import * as Telemetry from "./telemetry";
class MyComponent implement Telemetry.TelemetryComponent {
// can also be a simple string property
public get name() {
return "MyComponent";
}
fn() {
...
Telemetry.pushData({ ... }, this);
}
}
2nd Edit
Because you are using a module system, your module files are enough to make singletons, there's no need for a class to achieve that.
You can do this:
// telemetry.ts
let area: string;
export interface TelemetryData {
...
}
export function setArea(usedArea: string) {
area = usedArea;
}
export function pushData(data: TelemetryData): void {
...
}
Then:
Telemetry.setArea("ComponentA");
...
Telemetry.publishEvent(data);
The telemetry module will be created only once per page, so you can treat the entire module as a singleton.
Export only the functions that are needed.
Suppose I am writing a method that delegates part of its work to an existing method (A factory method invoking a constructor would be a good example).
I would like to be able to automatically add the arguments to the method I am writing based on the method it invokes. However, IntelliJ does not seem to have the right shortcut for this. For example:
I have
class Foo {
Foo(ArgClass arg);
}
and I've just created
class FooFactory {
Foo createFoo() {
return new Foo();
}
}
Is there a shortcut (or a sequence of them) that would get my factory to
class FooFactory {
Foo createFoo(ArgClass arg) {
return new Foo(arg);
}
}
without manually typing "arg"?
I recommend doing it like this. Copy & paste arg once here (| is text cursor):
class FooFactory {
Foo createFoo() {
return new Foo(arg|);
}
}
Invoke Alt+Enter and select the quick fix Create parameter 'arg'. The Change Signature refactoring dialog appears, type Ctrl+Enter to accept. Result:
class FooFactory {
Foo createFoo(ArgClass arg) {
return new Foo(arg);
}
}
Is there a way to obtain a friendship between classes in incr Tcl?
Consider the code below.
package require Itcl
::itcl::class A {
private {
proc f { } {
puts "==== A::f"
}
}
}
::itcl::class B {
public {
proc g { } {
puts "==== want to be able to call A::f"
}
}
}
I want A::f to be invisible outside A bur functions of B. How can I achieve this?
Itcl doesn't provide friends.
You can hack around this by constructing a call using namespace inscope, like so:
namespace inscope A {A::f}