8

私はあなたができることを持っています.engine.setState(<state class>)それはあなたが与えたクラスタイプをインスタンス化し、新しい状態で実行を開始します.

にはSelectFileStateに行くボタンがNewFileStateありNewFileState、 には に戻るボタンがありますSelectFileState

さて、 の冒頭でSelectFileState、私はインポートしてNewFileStateいます (したがって、後でクラスで行うことができますengine.setState(NewFileState)。 の冒頭でNewFileState、私もインポートしていSelectFileStateます (したがって、後で に戻ることができますSelectFileState)。

ただし、他の投稿で説明されているように、これにより循環インポートが作成されます。循環インポートは設計が悪いことを示しており、リファクタリングする必要があると言う人もいます..

使用する直前にインポートすることでこの問題を解決できることはわかっていSelectFileStateますが、正しい方法でリファクタリングしたいと思います。

今、私は疑問に思っています..それをどのようにリファクタリングしますか?

ありがとう。

編集Pydsignerは、2つのファイルを1つにマージすることを提案しています.2つのファイルは互いに非常に関連しているためです。ただし、循環依存関係を持つすべての状態を 1 つのファイルに入れることはできないため、そのためのより良い方法が必要です。何か案は?

2編集: 構文を使用せずfrom x import y、代わりにimport x. これは望ましい解決策ではありません。この種のことを修正する「Pythonic」の方法を知りたいです。ファイルをマージするだけでは、永久に解決することはできません。

コード:

SelectFileState

from states.state import State
from states.newfilestate import NewFileState

from elements.poster import Poster
from elements.label import Label
from elements.button import Button
from elements.trifader import TriFader

import glob
import os

class SelectFileState(State):
    def __init__(self, engine):
        super().__init__(engine)

    def create(self):
        self.engine.createElement((0, 0), Poster(self.engine.getImage('gui_loadsave')), 1)
        self.engine.createElement((168, 30), Label("Load a game", 40), 2)
        self.engine.createElement((400, 470), Button("New save", code=self.engine.createElement, args=((0, 0), TriFader(NewFileState, False), -240)), 3)

        ycounter = 150

        globs = glob.glob("save\\*.mcw")
        for file in globs:
            self.engine.createElement((200, ycounter), Button(os.path.basename(file)[:-4]), 2)
            ycounter += 50

NewFileState

from states.state import State
from states.selectfilestate import SelectFileState

from elements.poster import Poster
from elements.label import Label
from elements.button import Button
from elements.inputbox import InputBox
from elements.trifader import TriFader


class NewFileState(State):
    def __init__(self, engine):
        super().__init__(engine)

    def create(self):
        self.engine.createElement((0, 0), Poster(self.engine.getImage('gui_loadsave')), 1)
        self.engine.createElement((135, 30), Label("Make a new save", 40), 2)

        self.lvlname = self.engine.createElement((180, 212), InputBox(length=25, text="World name"), 2)
        self.engine.createElement((200, 240), Button(text="Ok", code=self.createSave, args=()), 2)

    def createSave(self):
        open("save\\" + self.lvlname.getText() + ".mcw", 'w')
        self.engine.createElement((0, 0), TriFader(SelectFileState), -240)
4

4 に答える 4

3

コードを見なくても、2 つのファイルをマージするのが最も理にかなっています。それらが非常に密接に絡み合っている場合は、おそらく奇妙な場所に何もなくてもそれらを組み合わせることができます.

于 2012-11-13T02:18:05.467 に答える
2

Python インポートでは、モジュールの先頭に表示する必要はありません。実際、それらは関数に表示される可能性があるため、NewFileState.py で SelectFileState のインポートを NewFileState.create に移動し、SelectFileState.py に同様の変更を加えることができます。

于 2012-11-13T02:38:09.943 に答える
0

ここでできることは、コードの実行時に相互クラスのみが必要になるため、クラスがインスタンス化され、メソッドが呼び出されるため、クラス名を親モジュールで使用できるようにすることです-「状態」およびそこから名前をインポートします:

州。初期化.py

from states.selectfilestate import SelectFileState
from states.newfilestate import NewFileState

この時点で、両方のサブモジュールが初期化されます。本体の実行中にモジュールの不完全なバージョンが「表示」states されますが、このモジュールはこの段階ではアクセスされていません。いずれかのクラスが実際にインスタンス化states.__init__.pyされると、実行が終了し、モジュールへの参照がstates完全なモジュール オブジェクトを指します。

state.selectfilestate で:

import states
...
        self.engine.createElement((0, 0), TriFader(states.SelectFileState), -240)

そして、state.newfilestare で:

import states
...
        self.engine.createElement((0, 0), TriFader(SelectFileState), -240)
于 2012-11-13T02:54:44.967 に答える
0

ディクショナリ マッピングで実際のクラス参照を非表示にし、クラス参照を渡す代わりに、実際のクラスにマップされる定数値を渡すことができます。これは、スタンドアロン モジュールの dict として保持することも、次の状態の取得を処理する別の StateManager クラスにラップすることもできます。

このアプローチの問題は、状態のリストと、定数からクラス参照へのマッピングを手動で更新する必要があることです。

実装例を次に示します。

states.const

# This module is states.const

(
    STATE_SELECT_FILE,
    STATE_NEW_FILE,
) = range(2) # manually update this number when you add/remove states

states.mapping

# This module is states.mapping
from states.const import *
from states.newfilestate import NewFileState
from states.selectfilestate import SelectFileState

STATE_MAPPING = {
    STATE_SELECT_FILE : SelectFileState,
    STATE_NEW_FILE : NewFileState,
}

SelectFileState

from states.const import STATE_NEW_FILE
# ... snip ...
... TriFader(STATE_NEW_FILE, False) ...

NewFileState

from states.const import STATE_SELECT_FILE
# ... snip ...
... TriFader(STATE_SELECT_FILE) ...

エンジン.setState()

from states.mapping import STATE_MAPPING

def setState(class_key):
    obj = STATE_MAPPING[class_key]()
    # ... do other stuff ...
于 2012-11-13T04:04:30.210 に答える