개요
객체지향 스타일은 다양하지만 Story Bakery 에선 다음 구조를 자주 사용합니다.
API 문서 주석
API 문서 주석의 상세한 체계적인 방식은, document-based-comment 를 참고하세요.
주로 moonwave 를 이용해서 주석을 작성합니다.
예제
--[=[
@class Class
Class 객체에 대한 설명
]=]
local Class = {}
Class.__index = Class
Class.__type = "Class"
export type Class = setmetatable(typeof({} :: {
--[=[
@prop Class.IsDestroyed boolean
설명
]=]
IsDestroyed: boolean,
--[=[
@prop Class.Maid Maid
설명
]=]
Maid: Maid.Maid,
--[=[
@prop Class.Name string
설명
]=]
Name: string,
_private: any,
}))
--#region Constructors
--[=[
@interface ClassParams
@within Class
Class 생성자에 전달되는 매개변수들의 타입입니다.
.Name string? -- 클래스의 이름입니다. 기본값은 "Name" 입니다.
]=]
export type ClassParams = {
Name: string?,
}
--[=[
Class 객체의 새 인스턴스를 생성합니다.
]=]
function Class.new(params: ClassParams?): Class
local params = params or {}
local self = setmetatable({}, Class)
self.IsDestroyed = false
self.Maid = Maid.new()
self.Property = params.Name or "Name"
self:_listenName()
return self
end
--#endregion Constructors
function self:_listenName()
-- do something...
end
--#region Methods
--[=[
객체를 파괴하고 모든 내부 리소스를 정리합니다.
]=]
function Class:Destroy()
if self.IsDestroyed then
return
end
self.IsDestroyed = true
self.Maid:Destroy()
-- 추가 동작
end
--#endregion Methods
--#region Functions
--[=[
이름으로부터 Class 객체를 검색합니다.
@param name string -- 검색할 클래스 이름
@return Class -- 검색된 클래스 객체
]=]
function Class.GetClassByName(name: string): Class
return classesByName[name] or error(`Failed to get Class from name "{Name}".`)
end
--#endregion Functions
블록 구분 규칙
--#region / --#endregion 은 Types, Constructors, Methods 와 같이 객체지향 구조의 큰 구획만 감쌉니다.
서비스, Require, 상수 등 일반 코드 블록은 빈 줄과 작성 순서로만 구분하며, -- 공통 조상 --, -- 외부 패키지 -- 같은 주석으로 감싸지 않습니다.
Require 블록은 외부 패키지 → 공통 조상 → 공통 조상의 하위 모듈 순서를 지키고, 각 항목은 문자열 literal alias 로 require("@Alias/Path") 형식만 사용합니다.
생성자와 내부 함수 작성 원칙:
- 생성자 이름은 언제나 camelCase 로 작성합니다.
- 내부 함수는 생성자나 메소드 안에서만 함께 사용하며, 기능 단위를 나누는 용도로만 둡니다.
- 내부 함수를 쪼개는 목적은 주석 없이도 함수 이름만으로 동작을 구분하도록 하기 위함입니다.
생성자
전부 camelCase 로 작성합니다
--#region Constructors
function Cleaner.new(params: CleanerParams?): Cleaner
local self = setmetatable({}, Cleaner)
-- do something...
return self
end
function Cleaner.fromInstance(instance: Instance, params: CleanerFromInstanceParams?): Cleaner
local self = Cleaner.new()
-- do something...
return self
end
기존에 생성한 걸 찾거나 얻는 게 아니라면 함수 형식으로 작성합니다
new
객체 생성은 new 로 처리합니다.
싱글턴
싱글턴 패턴의 모듈에도 .new() 를 사용해줍시다
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Signal = require("@Signal")
local Promise = require(Packages.Promise)
local CameraModules = ReplicatedStorage.CameraModules
local CameraManager = {}
CameraManager.__index = CameraManager
CameraManager.__type = "CameraManager"
--#region Constructors
function CameraManager.new(): CameraManager
end
--#endregion Constructors
--#region Methods
function CameraManager:GetCFrame(): CFrame
end
--#endregion Methods
return CameraManager.new()
혹은 싱글턴은 아니지만, 대부분의 상황에서 하나의 인스턴스만 필요하고
가끔씩 개별된 객체가 필요하다면, 싱글턴으로 만들기보단 Global{Object} 로 공통적으로 쓰일 수 있는 객체를 만듭니다.
local DyanmicTimer = {}
DyanmicTimer.__index = DyanmicTimer
-- ...
DyanmicTimer.GlobalTimer = DyanmicTimer.new()
return DyanmicTimer
Params
생성자에는 여러 인수나, params 가 필요할 수 있습니다 params 필수 여부는 params 가 얼마나 중요하나에 따라 달리 설정할 수 있습니다
params 에 대한 타입은 해당 params 를 사용하는 생성자나 메소드 위에 올려둡니다.
--#region Constructors
export type CleanerParams = {
}
function Cleaner.new(params: CleanerParams?): Cleaner
end
export type CleanerFromInstanceParams = {
}
function Cleaner.fromInstance(instance: Instance, params: CleanerFromInstanceParams?): Cleaner
end
--#endregion Constructors
Params 가 필수가 아니라면 local params = params or {} 를 통해 코드 맨 위에 정의해줍니다.
function Cleaner.new(params: CleanerParams?): Cleaner
local params = params or {}
local self = setmetatable({}, Cleaner)
-- ...
self.Name = params.Name or "Name"
-- ...
end
Params 가 필수고, 특정 인자값도 필수적이라면 or error() 를 이용할 수 있습니다
export type CarParams = {
Speed: number,
Optional: any?,
}
function Car.new(params: CarParams): Car
local self = setmetatable({}, Cleaner)
-- ...
self:_setSpeed(params.Speed or error(`Missing Speed`))
-- ...
end
속성
모듈이나 객체에 . 으로 인덱스하며, 함수가 아닌 변수들을 말합니다.
메소드
메소드는 객체에 : 으로 작동하는 함수들입니다.
함수
함수들은 모듈에 . 으로 작동하는 함수들입니다.