Я записал Python tsr, который опросил сервер время от времени (он вытянул свою частоту запросов с сервера), и распечатает для маркировки принтера. Было относительно хорошо.
Когда-то записанный в Python, я использовал py2exe на нем, тогда inno компилятор установки, затем поставивший интранет, и сделал, чтобы пользователь установил его.
Это не было большим, но это работало. Пользователи запустили бы его утром, и программа получит переключатель уничтожения от сервера ночью.
Обычно я использую следующие функции:
Уровень данных:
Для доступа к данным я создаю интерфейс для каждого объекта. В каждом интерфейсе перечислены все общедоступные методы доступа к данным для рассматриваемого объекта. Для хранения данных я также создаю типы контейнеров для каждого объекта, которые могут быть структурами или простыми классами только с данными. Я также полагаюсь на языковой набор данных, например списки, для хранения моих данных, поэтому я не связан с конкретным типом базы данных. После этого я создаю класс, который реализует интерфейсы данных, этот класс имеет весь SQL и обращается к базе данных, поэтому в случае изменения технологии хранения данных это единственный класс, который будет изменен.
Бизнес-уровень:
Выполняет всю логику с данными, как проверять, какие методы из интерфейсов данных должны вызываться и в каком порядке. Этот класс получает и "отправляет" данные в хранилище данных или графический интерфейс пользователя, используя контейнеры (например, списки), где типы данных являются моими контейнерами, упомянутыми выше.
Графический интерфейс:
Вызывает методы бизнес-логики и показывает / форматирует представление данных. Здесь нет никакой логики, кроме вызова правильных методов бизнес-логики.
Небольшой пример кода контейнера (C #)
//Interface for Department class data access. DataStorage assembly
namespace DataStorage
{
public interface IDepartmentDS
{
void Open(); //Open data conection
void Close(); //Close data conection
List<Repositories.Department> List(); //Gets all departments (from data base)
}
}
//This class holds all data regarded a department. There's no logic here. Repositories assembly
namespace Repositories
{
public class Department
{
[Browsable(false)]
public Department()
{
}
[Browsable(false)]
public Department(String Symbol, String Name)
{
this.Symbol = Symbol;
this.DeptName = Name;
}
public Department(Department department)
{
this.Symbol = department.Symbol;
this.DeptName = department.DeptName;
}
[Browsable(false)]
public String Symbol { get; set; }
public String DeptName { get; set; }
}
}
//This class implements the data manipulation itself, accessing the real database.
//However the data exchange outside this class is done via repositories classes and
//Generics - Lists mainly
public class DataStorage : IDepartmentDS
{
//Here I use to put generic functions to connect with the database, format stored
//procedure parameters list etc.
//Implementation of the List method declare in the Department Interface
List<Repositories.Department> IDepartmentDS.List()
{
String query = String.Format("SELECT * FROM {0}", DepartmentTable);
int rows = 0;
DataSet ds = ExecSqlCommand(query, out rows); //this method is private to this class
if (ds == null)
return null;
List<Repositories.Department> list = new List<Repositories.Department>();
foreach (DataRow row in ds.Tables[0].Rows)
{
list.Add(new Repositories.Department((String)row[DepFN_Symbol], (String)row[DepFN_DepName]));
//DepFN_Symbol and the others are just const variables representing the column index
}
return list;
}
}
public class DepartmentLogic
{
public DepartmentLogic()
{
.....
}
public List<Repositories.Department> GetAllDepartments()
{
//Here I create an Instance of the DataStorage but using the Department interface
//so I restrict the access to Department data methods only. It could be a good
//idea here to use the factory pattern.
IDepartmentDS department = (IDepartmentDS) new DataStorage();
department.Open();
List<Repositories.Department> departments = department.List();
department.Close();
return departments;
}
}
Этот пример бизнес-логики действительно очень прост, он просто показывает, как извлекать данные из уровня хранилища , но пока у вас есть доступ к данным, вы можете манипулировать ими так, как хотите. Просто комментарий здесь: возможно, это решение следует переосмыслить, если оно будет реализовано на очень загруженном сервере с тысячами запросов, потому что оно может использовать много памяти.
Для бизнес-логики, а также с точки зрения пользовательского интерфейса, все данные передаются между модулями с использованием контейнеров общего назначения, таких как списки. Точкой связи между всеми этими модулями являются классы контейнеров, поэтому все классы менее хорошо разделены.
UI делает запросы к классам бизнес-логики, поэтому он действует как поставщик услуг. Таким образом, изменение пользовательского интерфейса не повлияет на следующие классы.
Бизнес-логика запрашивает и отправляет данные в классы хранилища данных с использованием данных общего назначения, поэтому изменение технологии базы данных / хранилища не должно влиять на нее.
Я так делаю и пытаюсь улучшить;)
«Уровень» ваших данных, вероятно, должен быть больше, чем набор семантических запросов, и вы должны инкапсулировать его в API, иначе вашему слою бизнес-логики придется слишком много знать о реализации вашего уровня данных. Те же рассуждения, которые вы использовали между слоями графического интерфейса пользователя и бизнес-логики, должны применяться и для той же цели.