I'm trying to follow along with a C# design patterns book by writing my code in TypeScript. Perhaps this is my first mistake, but it's a way I enjoy to learn a language.
TypeScript doesn't support the abstract keyword for classes, so I am trying to simulate it. Maybe this is my second mistake.
Here is my interface and classes:
interface IEngine {
getSize(): number;
getTurbo(): boolean;
}
class AbstractEngine implements IEngine {
constructor(private size: number, private turbo: boolean) {
throw "Abstract class";
}
public getSize(): number {
return this.size;
}
public getTurbo(): boolean {
return this.turbo;
}
public toString(): string {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(this.constructor.toString());
var className = (results && results.length > 1) ? results[1] : '';
return className + " (" + this.size + ")";
}
}
class StandardEngine extends AbstractEngine {
constructor(size: number) {
// not turbo charged
super(size, false);
}
}
When trying to instantiate an AbstractEngine with new AbstractEngine(1, true) I get an "Abstract class" error as expected.
When trying to instantiate a StandardEngine with new StandardEngine(9000) I also get an "Abstract class" error.
Is there a way I can simulate an abstract class in TypeScript, have it unable to be instantiated, but still call super in a class that extends it? And what about simulating abstract methods, can I protect those and still call the super method?
As of today, TypeScript 1.6 is live and has support for the abstract keyword.
abstract class A {
foo(): number { return this.bar(); }
abstract bar(): number;
}
var a = new A(); // error, Cannot create an instance of the abstract class 'A'
class B extends A {
bar() { return 1; }
}
var b = new b(); // success, all abstracts are defined
I advise you not to do that. When the TypeScript compiler will implement a mechanism for abstract function, it is time to use it. But hacks that work at runtime are incomprehensible and degrade performance.
The interfaces are the great strength of TypeScript. They should be used massively.
Your example should be written like this:
interface Engine {
getSize(): number;
getTurbo(): boolean;
}
class StandardEngine implements Engine {
constructor(private size: number, private turbo: boolean) {
}
public getSize(): number {
return this.size;
}
public getTurbo(): boolean {
return this.turbo;
}
}
The simplest solution is often the best.
If you want to reuse code without a parent class which would then necessarily usable, the Handbook suggests Mixins. Mixins are a way of coping skills from several distinct entities.
Or with modules it is possible to keep private implementation (and therefore organize it as you want it) and export only interfaces and factories. An example:
module MyEngineModule {
export interface Engine {
getSize(): number;
getTurbo(): boolean;
}
export interface StandardEngine extends Engine {
}
export function makeStandardEngine(size: number, turbo: boolean): StandardEngine {
return new ImplStandardEngine(size, turbo);
}
// here classes are private and can inherit or use mixins…
class ImplEngine {
constructor(private size: number, private turbo: boolean) {
}
public getSize(): number {
return this.size;
}
public getTurbo(): boolean {
return this.turbo;
}
}
class ImplStandardEngine extends ImplEngine implements StandardEngine {
}
}
console.log(MyEngineModule.makeStandardEngine(123, true).getSize());
When calling the StandardEngine constructor, you have a call to super(size, false). This call into the base class is what is generating the second "Abstract class" error.
To simulate an abstract base class that will throw when instantiated, create an Init function that is called from your derived class.
class AbstractEngine implements IEngine {
private _size: number;
private _turbo: boolean;
constructor() {
throw "Abstract class";
}
init(size:number, turbo: boolean) {
this._size = size;
this._turbo = turbo;
}
}
class StandardEngine extends AbstractEngine {
constructor(size: number) {
// not turbo charged
// do not call super here
init(size, false);
}
}
An alternative solution would be to user a property that if set indicates that the constructor is being called from a child class it is safe to continue. This is shown below :
class AbstractEngine {
safe; // IMPORTANT : do not initialize
constructor(private size: number, private turbo: boolean) {
if(!this.safe) throw "Abstract class"; // IMPORTANT
}
}
class StandardEngine extends AbstractEngine {
constructor(size: number) {
this.safe = true; // IMPORTANT
super(size, false);
}
}
Related
I have a class with a nested, private class. I have a Builder, standard Java builder pattern, that constructs instances of this class. I don't want anyone outside of my class to be able to see my hidden class.
In Java I could do this:
public class Example {
private SneakyType doNotExposeThis;
private Example(Builder builder) {
// OK 'cause in Java you can access the private
// members of a nested class
doNotExposeThis = builder.doNotExposeThis;
}
private static class SneakyType {
SneakyType(String x) {
// stuff
}
}
public static class Builder {
private SneakyType doNotExposeThis;
public void addFoo(String something) {
doNotExposeThis = new SneakyType(something);
}
public Example build() { return new Example(this); }
}
}
But I can't figure out how to do the same in Kotlin:
class Example(builder: Builder) {
private lateinit var doNotExposeThis: SneakyType
init {
doNotExposeThis = builder.doNotExposeThis
}
class Builder {
// If private or internal I can't access it in Example.init
// and if public it gets exposed.
val doNotExposeThis: SneakyType
fun addFoo(something: String) {
// actual construction is quite a bit more complex
doNotExposeThis = SneakyType(something)
}
}
}
Note that for the sake of Java interop I want to keep my builder. I also want it because my object is complicated to construct and I want it to be immutable so I have a builder with lots of setters, adders, vals, etc. and then in init I construct a single immutable Example.
The only alternatives I see are:
Instead of have a SneakyType in my builder save all the info necessary to construct one and then construct it in Example. Works but adds a ton of complexity.
Give up on Example being immutable and allow the builder to call into it to set up a Sneaky
Expose the Sneaky
Is there no way to mimic the Java version?
I see two viable options:
Use the internal visibility modifier:
class Example private constructor(builder: Builder) {
private val doNotExposeThis: SneakyType
init {
doNotExposeThis = builder.doNotExposeThis
}
internal class SneakyType(x: String)
class Builder {
internal lateinit var doNotExposeThis: SneakyType
fun addFoo(something: String) {
doNotExposeThis = SneakyType(something)
}
fun build(): Example {
return Example(this)
}
}
}
This will make SneakyType only visible within your Kotlin compilation module.
Make Example independent of its builder (this is what I recommend):
class Example private constructor(private val doNotExposeThis: SneakyType) {
private class SneakyType(x: String)
class Builder {
private lateinit var doNotExposeThis: SneakyType
fun addFoo(something: String) {
doNotExposeThis = SneakyType(something)
}
fun build(): Example {
return Example(doNotExposeThis)
}
}
}
I am creating a base class(here called top) that I want to use to create a blue print for all its children. I am doing this by making abstract functions on the base so that the children have to have an implementation of that in order to be valid. Here is an example
interface ITopData { }
abstract class top{
constructor() { }
abstract test<T extends ITopData>(data: T): void;
}
interface IBottomData extends ITopData { }
class bottom extends top {
constructor() { super() }
test<IBottomData>(data) { return }
}
This is the desired code however when i write a class like this
class bad extends top {
constructor() { super() }
test(data: string) { return }
//these implementations also dont cause any complaints
//test<T extends string>(data) { return }
//test() { return }
}
What I want is for typescript to complain that class "bad" doesnt properly extend class "top". When I write this out though I get no complaints from my intellisense or my transpiler.
edit: I do get errors if a child class were to not have any implementation of the function, but the errors go when using any of the implementations shown above.
One thing to remember is that string matches interface ITopData {} - since the interface has no properties, any object type will match it.
While TypeScript 2.0 does not enforce the types based on the generic argument, if you specify the type for the parameter directly, you will get the compiler error. The semantics of the method parameter also stays the same.
interface ITopData {
// the interface must have at least one mandatory property,
// otherwise any object will match it
foo: number;
}
abstract class foo{
constructor() { }
abstract test(data: ITopData): void;
}
interface IBottomData extends ITopData { }
class bottom extends foo {
constructor() { super() }
test(data: IBottomData) { return }
}
class bad extends foo {
constructor() { super() }
test(data: string) { return; }
}
Alternatively, specify the generic type for the class instead of the method. This way you will also get compiler errors as soon as the types do not match
interface ITopData {
// the interface must have at least one mandatory property,
// otherwise any object will match it
foo: number;
}
abstract class foo<T extends ITopData>{
constructor() { }
abstract test(data: T): void;
}
interface IBottomData extends ITopData { }
class bad1 extends foo<IBottomData> {
constructor() { super() }
test(data: string) { return }
}
class bad2 extends foo<string> {
constructor() { super() }
test(data: string) { return; }
}
Given the classic coffee decorator example (copied from Wikipedia).
public interface Coffee {
public double getCost();
}
public class SimpleCoffee implements Coffee {
public double getCost() {
return 1;
}
}
public abstract class CoffeeDecorator implements Coffee {
protected final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee c) {
this.decoratedCoffee = c;
}
public double getCost() {
return decoratedCoffee.getCost();
}
}
class WithMilk extends CoffeeDecorator {
public WithMilk(Coffee c) {
super(c);
}
public double getCost() {
return super.getCost() + MILKCOST;
}
public int someAttribute;
}
class WithMocha extends CoffeeDecorator {
public WithMocha(Coffee c) {
super(c);
}
public double getCost() {
return super.getCost() + MOCHACOST;
}
}
Suppose I want my WithMocha cost to use someAttribute if the WithMilk decorator exists, how would one design such a decorator system?
Is the decorator pattern even the best approach?
No it isn't, as casting the coffee instance to a decorator would violate Liskovs substution principle.
As your question do not detail the real problem that you want to solve it's hard to give a proper answer.
If you want to construct objects where the different parts can interact the Builder pattern is a much better alternative.
Say, I have class A with method M:
private void M()
{
Do1();
Do2();
}
class B extends A.
Problem: I need Do2() to not to be executed when calling from an instance of B.
I have a couple of ideas but not sure which do not break OOP and SOLID rules.
Make Do2 virtual.
class A
{
protected virtual void Do2()
{
// Do something
}
}
class B
{
protected override void Do2()
{
// Do nothing
}
}
This solution looks weird to me because I override a method to "do nothing", when overriding is needed to "do something instead of something" or "do something in addition to something".
Create bool protected flag property
class A
{
protected virtual NeedCallDo2
{
get { return true; }
}
private void M()
{
Do1();
if (NeedCallDo2)
{
Do2();
}
}
}
class B
{
protected override NeedCallDo2
{
get { return false; }
}
}
This solution is also not perfect but I have a control of execution flow and can decide whether to call Do2 or not.
Pass constructor flag parameter
class A
{
private bool needCallDo2;
protected A(bool needCallDo2 = true)
{
this.needCallDo2 = needCallDo2;
}
private void M()
{
Do1();
if (this.needCallDo2)
{
Do2();
}
}
}
class B
{
public B()
: base(false)
{
}
}
This is a trick question! Given the solid-principles tag, there is no correct way to disable base class functionality, since that would violate liskov-substitution, which is the L in SOLID.
You could move the execution logic into an execution strategy class where class B uses a different strategy implementation than class A.
I wonder how to add state to the chain of decorators that will be available to the consumer. Given this simplified model:
abstract class AbstractPizza
{
public abstract print(...);
}
class Pizza : AbstractPizza
{
public int Size { get; set; }
public print(...);
}
abstract class AbstractPizzaDecorator
{
public Pizza:AbstractPizza;
public abstract print();
}
class HotPizzaDecorator : AbstractPizzaDecorator
{
public int Hotness { get; set; }
public print(...);
}
class CheesyPizzaDecorator : AbstractPizzaDecorator
{
public string Cheese { get; set; }
public print(...);
}
void Main()
{
BigPizza = new Pizza();
BigPizza.Size = 36;
HotBigPizza = new HotPizzaDecorator();
HotBigPizza.Pizza = BigPizza;
HotBigPizza.Hotness = 3;
HotBigCheesyPizza = new CheesyPizzaDecorator();
HotBigCheesyPizza.Pizza = HotBigPizza;
HotBigCheesyPizza.Cheese = "Blue";
HotBigCheesyPizza.print();
HotBigCheesyPizza.size = 28; // ERRRRRR !
}
Now if they all implement the print method and propagate that though the chain, it's all good. But how does that work for the state? I can't access the size property on the HotBigCheesyPizza.
What's the part that I'm missing? Wrong pattern?
Thanks for helping!
Cheers
The decorator pattern is for adding additional behavior to the decorated class without the client needing to adjust. Thus it is not intended for adding a new interface (e.g. hotness, cheese) to the thing being decorated.
A somewhat bad example of what it might be used for is where you want to change how size is calculated: you could create a MetricSizePizzaDecorator that converts the size to/from English/metric units. The client would not know the pizza has been decorated - it just calls getSize() and does whatever it needs to do with the result (for example, to calculate the price).
I would probably not use the decorator in my example, but the point is: it does not alter the interface. In fact, nearly all design patterns come down to that - adding variability to a design without changing interfaces.
one way of adding state is by using a self referential data structure (a list). but this uses the visitor pattern and does more than you probably want. this code is rewritten from A little Java, a few patterns
// a self referential data structure with different types of nodes
abstract class Pie
{
abstract Object accept(PieVisitor ask);
}
class Bottom extends Pie
{
Object accept(PieVisitor ask) { return ask.forBottom(this); }
public String toString() { return "crust"; }
}
class Topping extends Pie
{
Object topping;
Pie rest;
Topping(Object topping,Pie rest) { this.topping=topping; this.rest=rest; }
Object accept(PieVisitor ask) { return ask.forTopping(this); }
public String toString() { return topping+" "+rest.toString(); }
}
//a class to manage the data structure
interface PieManager
{
int addTopping(Object t);
int removeTopping(Object t);
int substituteTopping(Object n,Object o);
int occursTopping(Object o);
}
class APieManager implements PieManager
{
Pie p=new Bottom();
// note: any object that implements a rational version of equal() will work
public int addTopping(Object t)
{
p=new Topping(t,p);
return occursTopping(t);
}
public int removeTopping(Object t)
{
p=(Pie)p.accept(new RemoveVisitor(t));
return occursTopping(t);
}
public int substituteTopping(Object n,Object o)
{
p=(Pie)p.accept(new SubstituteVisitor(n,o));
return occursTopping(n);
}
public int occursTopping(Object o)
{
return ((Integer)p.accept(new OccursVisitor(o))).intValue();
}
public String toString() { return p.toString(); }
}
//these are the visitors
interface PieVisitor
{
Object forBottom(Bottom that);
Object forTopping(Topping that);
}
class OccursVisitor implements PieVisitor
{
Object a;
OccursVisitor(Object a) { this.a=a; }
public Object forBottom(Bottom that) { return new Integer(0); }
public Object forTopping(Topping that)
{
if(that.topping.equals(a))
return new Integer(((Integer)(that.rest.accept(this))).intValue()+1);
else return that.rest.accept(this);
}
}
class SubstituteVisitor implements PieVisitor
{
Object n,o;
SubstituteVisitor(Object n,Object o) { this.n=n; this.o=o; }
public Object forBottom(Bottom that) { return that; }
public Object forTopping(Topping that)
{
if(o.equals(that.topping))
that.topping=n;
that.rest.accept(this);
return that;
}
}
class RemoveVisitor implements PieVisitor
{
Object o;
RemoveVisitor(Object o) { this.o=o; }
public Object forBottom(Bottom that) { return new Bottom(); }
public Object forTopping(Topping that)
{
if(o.equals(that.topping))
return that.rest.accept(this);
else return new Topping(that.topping,(Pie)that.rest.accept(this));
}
}
public class TestVisitor
{
public static void main(String[] args)
{
// make a PieManager
PieManager pieManager=new APieManager();
// add some toppings
pieManager.addTopping(new Float(1.2));
pieManager.addTopping(new String("cheese"));
pieManager.addTopping(new String("onions"));
pieManager.addTopping(new String("cheese"));
pieManager.addTopping(new String("onions"));
pieManager.addTopping(new String("peperoni"));
System.out.println("pieManager="+pieManager);
// substitute anchovies for onions
int n=pieManager.substituteTopping(new String("anchovies"),new String("onions"));
System.out.println(n+" pieManager="+pieManager);
// remove the 1.2's
n=pieManager.removeTopping(new Float(1.2));
System.out.println(n+" pieManager="+pieManager);
// how many anchovies do we have?
System.out.println(pieManager.occursTopping(new String("anchovies"))+" anchovies");
}
}
I believe your component Pizza and your abstract decorator PizzaDecorator are supposed to share the same interface, that way each instance of the decorator is capable of the same operations as the core component Pizza.