最初に用語に関する注釈とその後の一般化。
「グローバル変数」は、プログラム内のどこにでもアクセスできるため、スコープはグローバルです。あなたの質問で参照している_variables
は、オブジェクトのスコープ内のプライベートフィールドです。それらは、そのオブジェクトで定義されているコードによってのみアクセスできます。しかし、あなたはあなたのオブジェクト内の私的な作業変数の蓄積について心配するのは正しいです。
オブジェクトを設計することは難しく、技術とアイデアは数十年の実践と研究で進化しました。 Michael Feathersによって紹介されたSOLID頭字語は、デザインを評価するための有用な基準を提供するオブジェクト指向設計の5つの原則をまとめたものです。ガンマ(Gamma)他による書籍、Design Patterns: Elements of Reusable Object-Oriented Softwareもまた、そして1994年に最初に出版され、オブジェクト指向プログラミングにおけるデザインの良い要約と分類を提供します。この本は、そのようなパターンの使用を実証するためのケーススタディとして文書エディタを使用しています。本書のSOLIDの原則とデザインパターンはどちらも抽象であり、プログラムの作成方法を教えてくれませんが、プログラマーが議論して評価できる共通のアイデアを提供しています。だから私は私の答えでこれらのツールを両方使うつもりですが、近年、ソフトウェア開発プロセスをさらに強化するために、具体的にはtest driven developmentとbehaviour driven developmentという追加の技術が開発されていることをご承知おきください。
SOLIDのSはSingle Responsibility Principleの略で、あなたの例を見るのに適しています。あなたのオブジェクトApplication
を呼び出し、プライベートな作業変数をグローバル変数として考えると、あなたは単一のオブジェクト内にアプリケーション全体を記述していることを示唆しています。あなたができることは、Application
を、単一の責任領域にもっと重点を置く多くの異なるオブジェクトに分離して開始することです。最初に私はApplication
オブジェクトの名前を変更すると考えました。私はEditorWindow
に行きました。下の私の例ではEditorWindow
もHeader
とDocumentView
を持っています。
で以下のコードをコンパイル:
valac -X -DGETTEXT_PACKAGE --pkg gtk+-3.0 text_editor_example.gs
-X -DGETTEXT_PACKAGE
の使用は、この回答の最後に説明されています。
[indent=4]
uses
Gtk
init
Intl.setlocale()
Gtk.init(ref args)
var document = new Text("Lorem Ipsum")
var header = new Header("My text editor")
var body = new DocumentView(document)
var editor = new EditorWindow(header, body)
var document_selector = new DocumentFileSelector(editor)
var load_new_content_command = new Load(document, document_selector)
header.add_item(new OpenButton(load_new_content_command))
editor.show_all()
Gtk.main()
class EditorWindow:Window
construct(header:Header, body:DocumentView)
this.window_position = WindowPosition.CENTER
this.set_default_size(400, 400)
this.destroy.connect(Gtk.main_quit)
this.set_titlebar(header)
var box = new Box(Gtk.Orientation.VERTICAL, 1)
box.pack_start(body, true, true, 0)
this.add(box)
class Header:HeaderBar
construct(title:string = "")
this.show_close_button = true
this.set_title(title)
def add_item(item:Widget)
this.pack_start(item)
class OpenButton:ToolButton
construct(command:Command)
this.icon_widget = new Image.from_icon_name(
"document-open",
IconSize.SMALL_TOOLBAR
)
this.clicked.connect(command.execute)
class DocumentView:ScrolledWindow
construct(document:TextBuffer)
var view = new TextView.with_buffer(document)
view.set_wrap_mode(Gtk.WrapMode.WORD)
this.add(view)
interface Command:Object
def abstract execute()
interface DocumentSelector:Object
def abstract select():bool
def abstract get_document():string
class Text:TextBuffer
construct (initial:string = "")
this.text = initial
class DocumentFileSelector:Object implements DocumentSelector
_parent:Window
_uri:string = ""
construct(parent:Window)
_parent = parent
def select():bool
var dialog = new FileChooserDialog("Open file",
_parent,
FileChooserAction.OPEN,
dgettext("gtk30", "_OK"),
ResponseType.ACCEPT,
dgettext("gtk30", "_Cancel"),
ResponseType.CANCEL
)
selected:bool = false
var response = dialog.run()
case response
when ResponseType.ACCEPT
_uri = dialog.get_uri()
selected = true
dialog.destroy()
return selected
def get_document():string
return "Reading the text from a URI is not implemented\n%s".printf(_uri)
class Load:Object implements Command
_receiver:TextBuffer
_document_selector:DocumentSelector
construct(receiver:TextBuffer, document_selector:DocumentSelector)
_receiver = receiver
_document_selector = document_selector
def execute()
if _document_selector.select()
_receiver.text = _document_selector.get_document()
グラフィックユーザーインターフェイスの一般的な高レベルパターンはmodel-view-controller (MVC)です。これは、オブジェクトを簡単に再利用して変更できるようにオブジェクトのデカップリングを行うことです。例ではdocument
がモデルを表すオブジェクトになっています。これを別個のオブジェクトにすることにより、同じデータを複数のビューで表示することができます。たとえば、StackOverflowの質問を書くときには、エディタウィンドウがありますが、プレビューもあります。両方とも同じデータの異なるビューです。
この例では、command patternを使用して、ヘッダーツールバーが別のオブジェクトにさらに分離されています。ツールバーの各ボタンには、関連するコマンドがあります。コマンドを別々のオブジェクトとして持つことにより、コマンドを再利用することができます。例えば、Ctrl-Oをバインドする鍵は、Load
コマンドを使用することもできます。このように、開いているドキュメントボタンにアタッチされたコマンドのコードは、Ctrl-Oにアタッチするために書き直す必要はありません。
コマンドパターンはインターフェイスを使用します。オブジェクトがメソッドを実装している限り、コマンドとして使用できます。 Load
コマンドは、ユーザーにどのURIを開くかを尋ねるオブジェクト用のインターフェイスも使用します。 Gtk +にはFileChooserNativeもあります。したがって、FileChooserDialog
の代わりにFileChooserNative
ダイアログを使用する場合は、DocumentSelector
インターフェイスを実装する新しいオブジェクトを作成し、代わりにLoad
コマンドに渡すだけで済みます。このようにオブジェクトをデカプリングすることで、プログラムの柔軟性が増し、プライベートフィールドの使用が各オブジェクトに限定されたままになります。
例として、コンパイル時にいくつかの警告:warning: Gtk.Stock has been deprecated since 3.10
がありました。ドキュメント・オープン 『またはラベル「_Open開いているドキュメントのアイコンthe GNOME developer documentation for Stock Items状態『アイコンという名前の使用』のために
- :この答えの例では、新しい方法を使用しています』。」だから私は
document-open
を使った。これらの名前は、ファイル選択ダイアログの[OK]ボタンのfreedesktop.org Icon Naming Specification
- からのものです。GNOME Developer documentationには「アイコンを使用しないでください。前のアンダースコアは、それが国際化され、
gettext
によって翻訳されたことを意味します。 gettext
は、翻訳ファイルである「ドメイン」を使用します。 GTK + 3の場合、ドメインはgtk30
となります。プログラムをコンパイルするときにgettext
を有効にするには、デフォルトドメインのマクロをCコンパイラに渡す必要があります。これが-X -DGETTEXT_PACKAGE
が必要な理由です。また、Genieプログラムでは、ロケールをランタイム環境に設定するためにIntl.setlocale()
が必要です。これはあなたのプログラムを実行するためにLC_ALL="zh_CN" ./text_editor_example
のようなものを使用して行われた場合、あなたがロケールが、これは私がGitHubので読んでいる洙はるかに明確なコードになります
@AIThomasをインストールしていることがあれば、中国でOKボタンが表示されます!あなたはそのような偉大な合成をしました!ありがとうございました! –