#c# #python
Вопрос:
У нас есть библиотека баз данных на C#, которую мы можем использовать следующим образом:
DatabaseConnection conn = DatabaseConnection.FromConnectionString("...");
Эта библиотека скрывает многие различия между различными ядрами баз данных, такими как имена функций SQL, имена параметров и спецификации и т.д.
Внутренне DatabaseConnection
класс является абстрактным классом, реализующим некоторые из основных методов, но FromConnectionString
метод проходит через список зарегистрированных специализированных типов, который обрабатывает фактические различия и создает объект нужного класса. Другими словами, я не получаю объект DatabaseConnection обратно, вместо этого я получаю объект MSSQLDatabaseConnection или OracleDatabaseConnection, которые, конечно, наследуются от DatabaseConnection.
Строка подключения содержит информацию о том, для какого типа ядра базы данных и версии предназначено это подключение.
Я хотел бы создать аналогичную библиотеку на Python. Является ли правильным подходом создание чего-то, что можно построить подобным образом?
conn = DatabaseConnection("...")
или использовать метод класса?
conn = DatabaseConnection.FromConnectionString("...")
возможно ли вообще первое, то есть… создание такого объекта и получение чего-то другого, специализированного объекта, в зависимости от данных в переданной строке?
Хорошо, позвольте мне задать другой вопрос… Каков питонический способ сделать это?
В принципе, я также хочу иметь базовый класс DatabaseConnection в Python, реализующий общие методы, и специализируюсь на производных классах, и где-то должен быть метод или функция, которые на основе строки подключения конструируют и возвращают правильный тип объекта.
Ответ №1:
Это возможно в Python, но, вероятно, это не лучший способ сделать это. Шаблон фабрики классов, по сути, является обходным путем для языков, в которых нет классов первого класса. Поскольку в Python есть классы первого класса, вы можете хранить класс в переменной и использовать этот класс непосредственно для создания экземпляров. Чтобы изменить созданный класс, сохраните в переменной другой класс.
Например:
class class1:
def greet(self):
print "hi"
class class2:
def greet(self):
print "hello"
maker = class1
obj1 = maker()
maker = class2
obj2 = maker()
obj1.greet() # prints "hi"
obj2.greet() # prints "hello"
Комментарии:
1. Хорошо, хм, не совсем то, что я имел в виду, но это дает мне представление о том, как реализовать «фабрику соединений по умолчанию», возможно, я воспользуюсь этой идеей, даже если она не совсем соответствовала тому, что я хотел, спасибо.
Ответ №2:
Python не волнует, почему вы возвращаете тип.
def DatabaseConnection( str ):
if ( IsOracle( str ) ):
return OracleConnection( str )
else:
return SomeOtherConnection( str )
Ответ №3:
Первый вариант абсолютно возможен и, на мой взгляд, предпочтительнее. В python на самом деле не так много магии, стоящей за конструкторами. Во всех смыслах и целях они такие же, как и любая другая функция. Я несколько раз использовал этот шаблон проектирования, чтобы указать, что класс не должен создаваться напрямую, например:
def DatabaseConnectionFromString(connection_string)
return _DatabaseConnection(connection_string)
def DatabaseConnectionFromSomethingElse(something_else)
connection_string = convert_something_else_into_string(something_else)
return _DatabaseConnection(connection_string)
class _DatabaseConnection(object):
def __init__(self, connection_string):
self.connection_string = connection_string
Конечно, это надуманный пример, но это должно дать вам общее представление.
ПРАВКА: Это также одна из областей, где наследование также не так осуждается в python. Вы также можете сделать это:
DatabaseConnection(object):
def __init__(self, connection_string):
self.connection_string = connection_string
DatabaseConnectionFromSomethingElse(object)
def __init__(self, something_else):
self.connection_string = convert_something_else_into_string(something_else)
Извините, что так многословно, но я хотел внести ясность.
Комментарии:
1. Спасибо, хотя и ваши, и ответы Glomeks в некотором роде отвечают на мой вопрос, мне не совсем нравится переименовывать базовый класс подобным образом
2. Забавно, что вы опубликовали это, в то время как я внес правку, которая не требует именования класса. Если это не сработает, дайте мне знать, и я уверен, что смогу помочь вам с чем-то еще.