const showThumbs = (() => {
// really private ;-)
const state = ref(props.enableThumbs)
return computed({
get: () => state.value,
set: value => {
state.value = value
}
})
})()
/*
-----------------------------------
Nejčastější použití je právě pro:
- Vytvoření privátního scope
- Enkapsulaci dat a logiky
- Vyhnutí se globálnímu scope
- Zachování stavu přes closure
-----------------------------------
* 1. Vytvoření privátního scope
* - proměnné uvnitř neuniknou ven
* - čisté API pro vnější svět
*/
const counter = (() => {
let count = 0 // privátní proměnná
return {
increment() { count++ },
getCount() { return count }
}
})()
/**
* 2. Vyhnutí se globálnímu scope
* - dočasné proměnné zůstanou lokální
* - neznečišťuje globální namespace
*/
(() => {
const temp = 'nějaká dočasná proměnná'
// temp existuje jen uvnitř, neznečišťuje globální scope
})()
/**
* 3. Modulární pattern
* - privátní metody a proměnné
* - veřejné API
*/
const module = (() => {
const privateVar = 'private'
const privateMethod = () => {
console.log(privateVar)
}
return {
publicMethod() {
privateMethod() // má přístup k privátním věcem
}
}
})()
/**
* 4. Closure pro zachování stavu
* - privátní stav
* - reaktivní hodnota
*/
const showThumbs = (() => {
const state = ref(props.enableThumbs) // privátní stav
return computed({
get: () => state.value,
set: (value) => {
state.value = value
}
})
})()
/**
* 5. Vyhnutí se konfliktům
* - lokální aliasy
* - izolace kódu
*/
(() => {
const $ = jQuery // lokální alias pro jQuery
// používání $ uvnitř neovlivní jiné knihovny používající $
})()
/**
* 6. Inicializace
* - nastavení při načtení
* - konfigurace
* - event listenery
*/
(() => {
// nějaká inicializace
const config = {
apiKey: 'xxx',
endpoint: 'https://api.example.com'
}
// nastavení event listenerů
document.addEventListener('DOMContentLoaded', () => {
// inicializace UI
})
// další setup
const init = () => {
// ...
}
init()
})()
Original source: https://michaelnthiessen.com/12-design-patterns-vue
// https://blog.logrocket.com/exploring-advanced-design-patterns-vue-js/
// + MORE ... builder, adapter more usable ...
// BUILDER
// FormBuilder.js
class FormBuilder {
constructor() {
this.formFields = [];
}
addTextField(name, label, placeholder = '') {
this.formFields.push({
type: 'text',
name,
label,
placeholder,
});
return this; // Return the builder instance for method chaining
}
addNumberField(...) {
// Add a number field
}
addSelectField(...) {
// Add a select field
}
build() {
return this.formFields;
}
}
export default FormBuilder;
// Form.vue
import FormBuilder from './helpers/FormBuilder';
export default {
data() {
return {
formFields: [],
formData: {}, // Add a data property to store the form data
};
},
created() {
/*
* Use the FormBuilder class and its methods
* to construct the `formFields` object array
* with different form fields.
*/
this.formFields = new FormBuilder()
.addTextField('name', 'Name')
.addNumberField(...)
.addSelectField(...)
.build();
},
methods: {
handleSubmit() {
// Log the form data when the form is submitted
console.log(this.formData);
},
},
};
// ADAPTER
// UserAdapter.js
class UserAdapter {
constructor(externalUserData) {
this.externalUserData = externalUserData;
}
adapt() {
/*
* Adapt the external user data to match
* the component's expected format.
*
* Considering the structure of the expected
* response, grab the right object array
* (`results`) and its only value.
*
* @link https://randomuser.me/api/
*/
const userData = this.externalUserData.results[0];
return {
name: `${userData.name.first} ${userData.name.last}`,
email: userData.email,
gender: userData.gender,
location: `${userData.location.city}, ${userData.location.country}`,
displayPic: userData.picture.large,
};
}
}
export default UserAdapter;
import UserAdapter from './UserAdapter';
export default {
data() {
return {
userAdapter: null,
user: null
};
},
created() {
/*
* Get user data from an external API
* with a different format.
*/
async created() {
try {
// Make an API call
const response = await fetch('...');
if (!response.ok) {
throw new Error('Failed to fetch external user data');
}
const externalUserData = await response.json();
/*
* Create an adapter to convert external weather data
* to the format expected by the component.
*/
this.userAdapter = new UserAdapter(externalUserData);
// Adapt the data to the component's expected format
this.user = this.userAdapter.adapt();
} catch (error) {
console.error('Error fetching external user data:', error);
this.errorMessage = 'Failed to load user data. Please try again later.';
}
},
}
};
// Composable pattern
// userPreferences.js
import { ref } from 'vue';
const theme = ref('light');
const language = ref('english');
const notifications = ref(true);
// Getter for theme
const getTheme = () => theme.value;
// Setter for theme
const setTheme = (newTheme) => {
theme.value = newTheme;
};
// Getter for language
const getLanguage = () => language.value;
// Setter for language
const setLanguage = (newLanguage) => {
language.value = newLanguage;
};
// Getter for notifications
const getNotificationsEnabled = () => notifications.value;
// Setter for notifications
const setNotificationsEnabled = (enabled) => {
notifications.value = enabled;
};
export {
getTheme,
setTheme,
getLanguage,
setLanguage,
getNotificationsEnabled,
setNotificationsEnabled,
};
// themeSelector.js
import { computed } from 'vue';
import { getTheme, setTheme } from '../utils/userPreferences';
export function useThemeSelection() {
const selectedTheme = computed({
get: () => getTheme(),
set: (newTheme) => setTheme(newTheme),
});
return {
selectedTheme,
};
}
// ThemeSelector.vue
<template>
<div>
<label for="theme-switch">Theme</label>
<select id="theme-switch" @change="handleChange" v-model="selectedTheme">
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</div>
</template>
<script>
import { defineComponent } from 'vue';
import { useThemeSelection } from '../composables/themeSelector';
export default defineComponent({
setup() {
const { selectedTheme } = useThemeSelection();
const handleChange = (event) => {
const newTheme = event.target.value;
selectedTheme.value = newTheme; // Set the new theme
};
return {
selectedTheme,
handleChange,
};
},
});
</script>
// AnyOther.vue
<template>
<div class="settings">
<div class="settings-row">
<ThemeSelector />
<div :class="selectedTheme">
Here's how the {{ selectedTheme }} theme looks like.
</div>
</div>
</div>
</template>
<script>
import { defineComponent } from 'vue';
import { useThemeSelection } from './composables/themeSelector';
import ThemeSelector from './components/ThemeSelector';
export default defineComponent({
setup() {
const { selectedTheme } = useThemeSelection();
return {
selectedTheme,
};
},
components: {
ThemeSelector
},
});
</script>
<style>
.light {
background-color: #fff;
color: #000;
}
.dark {
background-color: #000;
color: #fff;
}
</style>
/*
https://blog.carlosrojas.dev/quick-reference-guide-to-design-patterns-in-js-1ebeb1e1c605
*/
/* Singleton */
class Animal {
constructor() {
if (typeof Animal.instance === 'object') {
return Animal.instance;
}
Animal.instance = this;
return this;
}
}
export default Animal;
/* Prototype */
class Fruit {
constructor(name, weight) {
this.name = name;
this.weight = weight;
}
clone() {
return new Fruit(this.name, this.weight);
}
}
export default Fruit;
const apple = new Fruit('Apple', 150);
const clonedApple = apple.clone();
console.log(apple); // Originální ovoce
console.log(clonedApple); // Klonované ovoce
/* Factory */
class MovieFactory {
create(genre) {
if (genre === 'Adventure') return new Movie(genre, 10000);
if (genre === 'Action') return new Movie(genre, 11000);
}
}
class Movie {
constructor(type, price) {
this.type = type;
this.price = price;
}
}
export default MovieFactory;
/* Abstract Factory */
function foodProducer(kind) {
if (kind === 'protein') return proteinPattern;
if (kind === 'fat') return fatPattern;
return carbohydratesPattern;
}
function proteinPattern() {
return new Protein();
}
function fatPattern() {
return new Fat();
}
function carbohydratesPattern() {
return new Carbohydrates();
}
class Protein {
info() {
return 'I am Protein.';
}
}
class Fat {
info() {
return 'I am Fat.';
}
}
class Carbohydrates {
info() {
return 'I am carbohydrates.';
}
}
export default foodProducer;
/* Adapter */
class Soldier {
constructor(level) {
this.level = level;
}
attack() {
return this.level * 1;
}
}
class SuperSoldier {
constructor(level) {
this.level = level;
}
attackWithShield() {
return this.level * 10;
}
}
class SoldierAdapter {
constructor(superSoldier) {
this.superSoldier = superSoldier;
}
attack() {
return this.superSoldier.attackWithShield();
}
}
export { Soldier, SuperSoldier, SoldierAdapter };
// Vytvoření instance SuperSoldier
const superSoldier = new SuperSoldier(5);
// Vytvoření instance SoldierAdapter, který přijímá SuperSoldier jako argument
const soldierAdapter = new SoldierAdapter(superSoldier);
// Volání metody attack() na SoldierAdapteru, která skutečně volá attackWithShield() u SuperSoldiera
const result = soldierAdapter.attack();
console.log(result); // Vypíše: 50 (5 * 10)
/* Bridge */
class Soldier {
constructor(weapon) {
this.weapon = weapon;
}
}
class SuperSoldier extends Soldier {
constructor(weapon) {
super(weapon);
}
attack() {
return 'SuperSoldier, Weapon: ' + this.weapon.get();
}
}
class IronMan extends Soldier {
constructor(weapon) {
super(weapon);
}
attack() {
return 'Ironman, Weapon: ' + this.ink.get();
}
}
class Weapon {
constructor(type) {
this.type = type;
}
get() {
return this.type;
}
}
class Shield extends Weapon {
constructor() {
super('shield');
}
}
class Rocket extends Weapon {
constructor() {
super('rocket');
}
}
export { SuperSoldier, IronMan, Shield, Rocket };
// Vytvoření instancí zbraní
const shield = new Shield();
const rocket = new Rocket();
// Vytvoření instancí vojáků s různými zbraněmi
const superSoldier = new SuperSoldier(shield);
const ironMan = new IronMan(rocket);
// Útoky vojáků
console.log(superSoldier.attack()); // Vypíše: SuperSoldier, Weapon: shield
console.log(ironMan.attack()); // Vypíše: Ironman, Weapon: rocket
/* Composite */
//Equipment
class Equipment {
getPrice() {
return this.price || 0;
}
getName() {
return this.name;
}
setName(name) {
this.name = name;
}
}
class Pattern extends Equipment {
constructor() {
super();
this.equipments = [];
}
add(equipment) {
this.equipments.push(equipment);
}
getPrice() {
return this.equipments
.map(equipment => {
return equipment.getPrice();
})
.reduce((a, b) => {
return a + b;
});
}
}
class Cabbinet extends Pattern {
constructor() {
super();
this.setName('cabbinet');
}
}
// --- leafs ---
class FloppyDisk extends Equipment {
constructor() {
super();
this.setName('Floppy Disk');
this.price = 70;
}
}
class HardDrive extends Equipment {
constructor() {
super();
this.setName('Hard Drive');
this.price = 250;
}
}
class Memory extends Equipment {
constructor() {
super();
this.setName('Memory');
this.price = 280;
}
}
export { Cabbinet, FloppyDisk, HardDrive, Memory };
// Vytvoření jednotlivých listových tříd (FloppyDisk, HardDrive, Memory)
const floppyDisk = new FloppyDisk();
const hardDrive = new HardDrive();
const memory = new Memory();
// Vytvoření skříně a přidání jednotlivých listových tříd do skříně
const cabbinet = new Cabbinet();
cabbinet.add(floppyDisk);
cabbinet.add(hardDrive);
cabbinet.add(memory);
// Získání celkové ceny skříně
const totalPrice = cabbinet.getPrice();
console.log(`Total Price: ${totalPrice}`); // Vypíše: Total Price: 600
/* Decorator */
class Notification {
constructor(kind) {
this.kind = kind || "Generic";
}
getInfo() {
return `I'm a ${this.kind} Notification`;
}
}
class FacebookNotification extends Notification {
constructor() {
super("Facebook");
}
setNotification(msg) {
this.message = msg;
}
getInfo() {
return `${super.getInfo()} with the message: ${this.message}`;
}
}
class SMSNotification extends Notification {
constructor() {
super("SMS");
}
getInfo() {
return super.getInfo();
}
}
export { FacebookNotification, SMSNotification };
// Vytvoření instance SMSNotification
const smsNotification = new SMSNotification();
// Dekorace SMSNotification pomocí FacebookNotificationDecorator
const decoratedNotification = new FacebookNotificationDecorator(smsNotification);
// Získání informací o dekorované notifikaci
console.log(decoratedNotification.getInfo());
// Vypíše: I'm a SMS Notification decorated with Facebook feature
/* Facade */
class Cart {
constructor() {
this.discount = new Discount();
this.shipping = new Shipping();
this.fees = new Fees();
}
calc(price) {
price = this.discount.calc(price);
price = this.fees.calc(price);
price += this.shipping.calc();
return price;
}
}
class Discount {
calc(value) {
return value * 0.85;
}
}
class Shipping {
calc() {
return 500;
}
}
class Fees {
calc(value) {
return value * 1.1;
}
}
export default Cart;
/* FlyWeight */
class Ingredient {
constructor(name) {
this.name = name;
}
getInfo() {
return `I'm a ${this.name}`
}
}
class Ingredients {
constructor() {
this.ingredients = {};
}
create(name) {
let ingredient = this.ingredients[name];
if (ingredient) return ingredient;
this.ingredients[name] = new Ingredient(name);
return this.ingredients[name];
}
}
export { Ingredients };
/* Proxy */
class Plane {
fly() {
return 'flying';
}
}
class PilotProxy {
constructor(pilot) {
this.pilot = pilot;
}
fly() {
return this.pilot.age < 18 ? `too young to fly` : new Plane().fly();
}
}
class Pilot {
constructor(age) {
this.age = age;
}
}
export { Plane, PilotProxy, Pilot };
/* Iterator */
class Iterator {
constructor(el) {
this.index = 0;
this.elements = el;
}
next() {
return this.elements[this.index++];
}
hasNext() {
return this.index < this.elements.length;
}
}
export default Iterator;
// Importujte váš Iterator
import Iterator from './Iterator';
// Vytvořte nějakou kolekci dat (v tomto případě pole).
const collection = ['Prvek 1', 'Prvek 2', 'Prvek 3'];
// Vytvořte instanci Iteratoru, předávejte kolekci jako argument konstruktoru.
const iterator = new Iterator(collection);
// Projděte kolekci pomocí Iteratoru.
while (iterator.hasNext()) {
const element = iterator.next();
console.log(element);
}
/* Mediator */
class TrafficTower {
constructor() {
this.airplanes = [];
}
getPositions() {
return this.airplanes.map(airplane => {
return airplane.position.showPosition();
});
}
}
class Airplane {
constructor(position, trafficTower) {
this.position = position;
this.trafficTower = trafficTower;
this.trafficTower.airplanes.push(this);
}
getPositions() {
return this.trafficTower.getPositions();
}
}
class Position {
constructor(x,y) {
this.x = x;
this.y = y;
}
showPosition() {
return `My Position is ${x} and ${y}`;
}
}
export { TrafficTower, Airplane, Position };
const trafficTower = new TrafficTower();
const airplane1 = new Airplane(new Position(10, 20), trafficTower);
const airplane2 = new Airplane(new Position(30, 40), trafficTower);
// Informovat TrafficTower o pozici letadla.
airplane1.getPositions();
// Získat informace o pozicích ostatních letadel pomocí TrafficTower.
airplane2.getPositions();
/* State */
class OrderStatus {
constructor(name, nextStatus) {
this.name = name;
this.nextStatus = nextStatus;
}
next() {
return new this.nextStatus();
}
}
class WaitingForPayment extends OrderStatus {
constructor() {
super('waitingForPayment', Shipping);
}
}
class Shipping extends OrderStatus {
constructor() {
super('shipping', Delivered);
}
}
class Delivered extends OrderStatus {
constructor() {
super('delivered', Delivered);
}
}
class Order {
constructor() {
this.state = new WaitingForPayment();
}
nextPattern() {
this.state = this.state.next();
}
}
export default Order;
// Vytvořte instanci objednávky
const order = new Order();
// Zjistěte aktuální stav
console.log(order.state.name); // Výstup: 'waitingForPayment'
// Přejděte na další stav
order.nextPattern();
// Zjistěte nový stav
console.log(order.state.name); // Výstup: 'shipping'
// Přejděte na další stav
order.nextPattern();
// Zjistěte nový stav
console.log(order.state.name); // Výstup: 'delivered'
/* Strategy */
class ShoppingCart {
constructor(discount) {
this.discount = discount;
this.amount = 0;
}
checkout() {
return this.discount(this.amount);
}
setAmount(amount) {
this.amount = amount;
}
}
function guest(amount) {
return amount;
}
function regular(amount) {
return amount * 0.9;
}
function premium(amount) {
return amount * 0.8;
}
export { ShoppingCart, guest, regular, premium };
// Importujte třídu ShoppingCart a slevové strategie
import { ShoppingCart, guest, regular, premium } from './ShoppingCart';
// Vytvořte instanci nákupního košíku s různými slevovými strategiemi
const cartGuest = new ShoppingCart(guest);
const cartRegular = new ShoppingCart(regular);
const cartPremium = new ShoppingCart(premium);
// Nastavte množství v košíku
cartGuest.setAmount(100);
cartRegular.setAmount(100);
cartPremium.setAmount(100);
// Proveďte platbu s různými slevovými strategiemi
console.log(cartGuest.checkout()); // Výstup: 100 (žádná sleva)
console.log(cartRegular.checkout()); // Výstup: 90 (10% sleva pro běžného zákazníka)
console.log(cartPremium.checkout()); // Výstup: 80 (20% sleva pro prémiového zákazníka)
/* Template */
class Tax {
calc(value) {
if (value >= 1000) value = this.overThousand(value);
return this.complementaryFee(value);
}
complementaryFee(value) {
return value + 10;
}
}
class VAT extends Tax {
constructor() {
super();
}
overThousand(value) {
return value * 1.1;
}
}
class GST extends Tax {
constructor() {
super();
}
overThousand(value) {
return value * 1.2;
}
}
export { VAT, GST };
// Importujte třídy VAT a GST
import { VAT, GST } from './Tax';
// Vytvořte instanci třídy VAT a provedte výpočet daně
const vatTax = new VAT();
console.log(vatTax.calc(1200)); // Výstup: 1320 (včetně přirážky pro hodnoty nad 1000)
// Vytvořte instanci třídy GST a provedte výpočet daně
const gstTax = new GST();
console.log(gstTax.calc(1200)); // Výstup: 1440 (včetně přirážky pro hodnoty nad 1000)
// Staré rozhraní
class OldCar {
getSpeedInMPH() {
return 60;
}
}
// Nové rozhraní
class NewCar {
getSpeedInKPH() {
return 100;
}
}
class CarAdapter {
constructor(newCar) {
this.newCar = newCar;
}
// Adapter převede metodu getSpeedInMPH() na metodu getSpeed() pro kompatibilitu
getSpeed() {
return this.convertMPHtoKPH(this.newCar.getSpeedInKPH());
}
convertMPHtoKPH(mph) {
return mph * 1.60934;
}
}
const newCar = new NewCar();
const adaptedCar = new CarAdapter(newCar);
console.log("Nové auto (v KPH):", newCar.getSpeedInKPH()); // Vypíše "Nové auto (v KPH): 100"
console.log("Staré auto (v MPH):", adaptedCar.getSpeed()); // Vy
// We declare our prototype object with two methods
const enemy = {
attack: () => console.log("Pim Pam Pum!"),
flyAway: () => console.log("Flyyyy like an eagle!")
}
// We declare another object that will inherit from our prototype
const bug1 = {
name: "Buggy McFly",
phrase: "Your debugger doesn't work with me!"
}
// With setPrototypeOf we set the prototype of our object
Object.setPrototypeOf(bug1, enemy)
// With getPrototypeOf we read the prototype and confirm the previous has worked
console.log(Object.getPrototypeOf(bug1)) // { attack: [Function: attack], flyAway: [Function: flyAway] }
console.log(bug1.phrase) // Your debugger doesn't work with me!
console.log(bug1.attack()) // Pim Pam Pum!
console.log(bug1.flyAway()) // Flyyyy like an eagle!
// Abstraktní třída definující Factory Method
class AnimalFactory {
createAnimal() {
throw new Error("Metoda createAnimal musí být implementována.");
}
}
// Konkrétní třída implementující Factory Method
class DogFactory extends AnimalFactory {
createAnimal() {
return new Dog();
}
}
class CatFactory extends AnimalFactory {
createAnimal() {
return new Cat();
}
}
// Abstraktní třída reprezentující objekty, které budeme vytvářet
class Animal {
makeSound() {
throw new Error("Metoda makeSound musí být implementována.");
}
}
// Konkrétní třídy reprezentující objekty, které budeme vytvářet
class Dog extends Animal {
makeSound() {
console.log("Haf haf!");
}
}
class Cat extends Animal {
makeSound() {
console.log("Mňau mňau!");
}
}
// Použití Factory Method Pattern
function createAndMakeSound(animalFactory) {
const animal = animalFactory.createAnimal();
animal.makeSound();
}
// Použití Factory Method Pattern s různými Factory
const dogFactory = new DogFactory();
const catFactory = new CatFactory();
createAndMakeSound(dogFactory); // Vypíše "Haf haf!"
createAndMakeSound(catFactory); // Vypíše "Mňau mňau!"
class Singleton {
static instance = null;
constructor() {
if (Singleton.instance) {
throw new Error("Singleton instance already exists. Use getInstance() method to access it.");
}
// Inicializace Singletonu zde
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
someMethod() {
console.log("Metoda Singletonu");
}
}
// Použití Singletonu
const singletonInstance1 = Singleton.getInstance();
const singletonInstance2 = Singleton.getInstance(); // Tady bude vyvolána chyba
console.log(singletonInstance1 === singletonInstance2); // Vrátí true, protože se jedná o stejnou instanci
singletonInstance1.someMethod(); // Vypíše "Metoda Singletonu"
/*
URL: https://learn.coderslang.com/0076-javascript-design-patterns-builder/
*/
// how create object from literal
const Employee = {
isAdmin: false,
getRole: function() {
return this.isAdmin ? 'Admin' : 'RegularEmp';
};
};
const emp1 = Object.create(Employee);
emp1.getRole(); //'RegularEmp'
const emp2 = Object.create(Employee);
emp2.isAdmin = true;
emp2.getRole(); //'Admin'
// BUILDER PATTERN (prenasi a pomaha tvorit objekty s mandatory parametry, nepovinne vytvori separatne)
class OTG {
constructor(model, color, maxTemperature, maxTimeSelection) {
this.model = model;
this.title = 'OTG';
this.color = color;
this.maxTemperature = maxTemperature || 150;
this.maxTimeSelection = maxTimeSelection || 30;
}
}
const redOTG = new OTG('LG', 'red');
const highTempOTG = new OTG('LG', 'black', 200);
const highendTimeOTG = new OTG('LG', 'red', '150', '60');
class OTGBuilder {
constructor(model, color) {
this.model = model;
this.title = 'OTG';
this.color = color;
}
setMaxTemperature(temp) {
this.maxTemperature = temp;
return this;
}
setMaxTimeSelection(maxTime) {
this.maxTimeSelection = maxTime;
return this;
}
build() {
return new OTG(this.model, this.color,
this.maxTemperature, this.maxTimeSelection);
}
}
const basicOTG = new OTGBuilder('MorphyRichards', 'Black')
.setMaxTemperature(250)
.setMaxTimeSelection(60)
.build();
// or without mandatory params
const default = new OTGBuilder('Generic OTG', 'White')
.build();
/*
URL: https://learn.coderslang.com/0116-javascript-design-patterns-decorator/
*/
class Headphone {
constructor(model, color) {
this.model = model;
this.color = color;
}
getPrice() {
return 100;
}
}
class WirelessHeadPhone extends Headphone {
constructor(model, color) {
super(model, color);
this.isWired = false;
}
getPrice() {
return 150;
}
}
class WaterproofHeadPhone extends Headphone {
constructor(model, color) {
super(model, color);
this.isWaterproof = true;
}
getPrice() {
return 120;
}
}
class WaterProofAndWirelessHeadphone extends Headphone {
constructor(model, color) {
super(model, color);
this.isWaterproof = true;
this.isWired = false;
}
getPrice() {
return 170;
}
}
class BabyEarHeadphone extends Headphone {
constructor() {
super(model, color);
this.size = 'Small';
}
getPrice() {
return 80;
}
}