软件开发中的抽象无意义。数据库





5.00/5 (1投票)
抽象方法在数据库领域的应用。
- 下载数据库演示项目源代码 - 4 MB
- 下载附加文件 - 2.4 KB
- 下载示例数据库转储 - 220 KB
- 下载海帕克斯和泰可星表生成器 - 134 KB
- 下载示例 SQL Server 数据库转储 - 220 KB
- 下载数据库回归样本 - 31 KB
- 下载迭代回归样本 - 30.5 KB
- 下载 2D 图表示例 - 453 KB
- 下载 3D 图表示例 - 137 KB
- 下载数据库+数字图像处理示例 - 367 KB
- 下载 NASA/IPAC 银河系外数据库示例 - 12.9 KB
有用链接
- 通用工程软件主页
- 原文
- 软件开发中的抽象无意义。Outlook
- 软件开发中的抽象胡言乱语。实时
- Microsoft Visual Studio Express
- SQL Server Express
- Oracle Express Edition
- 范畴论
- NASA/IPAC 银河系外数据库
- 海帕克斯和泰可星表
1 简介。
本文是对我之前关于 常见问题 和 实时性 的文章的进一步发展。本文依赖于之前的文章。我的示例通过“序列化”的示例完成,其中数据集已序列化。使用这些示例不需要 SQL Server 数据库。
重要提示:演示解决方案包含 OracleTableProvider
项目。该项目旨在支持 Oracle 客户端。如果未安装 Oracle 客户端,则应从解决方案中排除 OracleTableProvider
项目。
2 背景
数据库域包含以下基本类型。
IDataSetProvider
:此接口由任何提供DataSet
的对象实现。IDataSetConsumer
:此接口由任何使用DataSet
的对象实现。DataSetArrow
:此箭头的源(或目标)应实现IDataSetConsumer
(或IDataSetProvider
)接口。
以下代码包含这些基本类型。
/// <summary> /// Provider of data set /// </summary> public interface IDataSetProvider { /// <summary> /// Provided data set /// </summary> DataSet DataSet { get; } /// <summary> /// Factory. This object can be null. It is not null for databases (SQL Server, Oracle, ...) /// </summary> IDataSetFactory Factory { get; set; } /// <summary> /// Change event /// </summary> event Action<DataSet> Change; }
/// <summary> /// Data set consumer /// </summary> public interface IDataSetConsumer { /// <summary> /// Adds data set /// </summary> /// <param name="dataSet">Data set to add</param> void Add(DataSet dataSet); /// <summary> /// Removes data set /// </summary> /// <param name="dataSet">Data set to remove</param> void Remove(DataSet dataSet); /// <summary> /// Factory /// </summary> IDataSetFactory Factory { get; set; } /// <summary> /// Add event /// </summary> event Action<DataSet> OnAdd; /// <summary> /// Add event /// </summary> event Action<DataSet> OnRemome; }
/// <summary> /// Arrow between data set provider and data set consumer /// </summary> [SerializableAttribute()] public class DataSetArrow : CategoryArrow, ISerializable, IRemovableObject { #region Fields /// <summary> /// Source /// </summary> protected IDataSetConsumer source; /// <summary> /// Target /// </summary> protected IDataSetProvider target; #endregion #region Constructors /// <summary> /// Default constructor /// </summary> public DataSetArrow() { } /// <summary> /// Deserialization constructor /// </summary> /// <param name="info">Serialization info</param> /// <param name="context">Streaming context</param> public DataSetArrow(SerializationInfo info, StreamingContext context) { } #endregion #region ISerializable Members /// <summary> /// ISerializable interface implementation /// </summary> /// <param name="info">Serialization info</param> /// <param name="context">Streaming context</param> public void GetObjectData(SerializationInfo info, StreamingContext context) { } #endregion #region ICategoryArrow Members /// <summary> /// The source of this arrow /// </summary> public override ICategoryObject Source { get { return source as ICategoryObject; } set { source = value.GetSource<IDataSetConsumer>(); } } /// <summary> /// The target of this arrow /// </summary> public override ICategoryObject Target { get { return target as ICategoryObject; } set { target = value.GetTarget<IDataSetProvider>(); source.Factory = target.Factory; source.Add(target.DataSet); } } #endregion #region IRemovableObject Members /// <summary> /// The post remove operation /// </summary> public void RemoveObject() { if (source != null & target != null) { if (target.DataSet != null) { source.Remove(target.DataSet); } } } #endregion }
下图显示了这些基本对象的示例。

IPAC 是从 NASA/IPAC 银河系外数据库获取的数据集的提供者。Chart 是数据集的消费者。Link 是 DataSetArrow
类型的对象。数据集提供者与数据集消费者分离是 桥接模式 的一种实现,下图展示了不同的消费者如何与不同的提供者连接。
任何数据集提供者都可以被另一个提供者替换。以下 3 张图片分别代表从 Sql Server、Oracle 和序列化数据集中获取的相同数据集。
我的示例通过序列化数据集来完成,以实现自主性。
3 数据集提供者
3.1 数据库数据集
数据集可以从不同的数据库 (SQL Server、Oracle 等) 获取。在这种情况下,IDataSetProvider
的 Factory
属性不应为 null。此属性的类型为 IDataSetFactory
。
/// <summary> /// Factory for creating data set metatata from connection /// </summary> public interface IDataSetFactory { /// <summary> /// Name of factory /// </summary> string FactoryName { get; } /// <summary> /// Creates connection /// </summary> DbConnection Connection { get; } /// <summary> /// Command /// </summary> DbCommand Command { get; } /// <summary> /// Gets metadata data set from connection /// </summary> /// <param name="connection">The connection</param> /// <returns>The metadata data set</returns> DataSet GetData(DbConnection connection); /// <summary> /// Gets metadata data set from connection string /// </summary> /// <param name="connectionString">The connection</param> /// <returns>The metadata data set</returns> DataSet GetData(string connectionString); /// <summary> /// Data adapter /// </summary> IDbDataAdapter Adapter { get; } // Full code is contained in the source file }
以下类图显示了上述接口的不同实现。
以下代码代表 SQL Server 和 Oracle 的此接口实现。
/// <summary> /// Factory of SQL Server /// </summary> public class SQLServerFactory : IDataSetFactory { #region IDataSetFactory Members /// <summary> /// Name of factory /// </summary> string IDataSetFactory.FactoryName { get { return "SQL Server"; } } /// <summary> /// Creates connection /// </summary> System.Data.Common.DbConnection IDataSetFactory.Connection { get { return new SqlConnection(); } } /// <summary> /// Command /// </summary> System.Data.Common.DbCommand IDataSetFactory.Command { get { return new SqlCommand(); } } // Full code is contained in the source file #endregion }
/// <summary> /// Oracle data set factory /// </summary> public class OracleFactory : IDataSetFactory { public static readonly OracleFactory Singleton = new OracleFactory(); private OracleFactory() { } #region IDataSetFactory Members /// <summary> /// Creates connection /// </summary> public System.Data.Common.DbConnection Connection { get { return new OracleConnection(); } } /// <summary> /// Command /// </summary> public System.Data.Common.DbCommand Command { get { return new OracleCommand(); } } // Full code is contained in the source file #endregion }
3.2 文件数据集
DataSet 类是可序列化的。SavedDataProvider
仅序列化数据集。以下代码代表其实现。
/// <summary> /// Data provider from xml /// </summary> [Serializable()] public class SavedDataProvider : CategoryObject, ISerializable, IDataSetProvider { #region Fields /// <summary> /// Data set /// </summary> protected DataSet dataSet = new DataSet(); /// <summary> /// Change event /// </summary> protected Action<DataSet> change = (DataSet ds) => { }; #endregion #region Ctor /// <summary> /// Default Constructor /// </summary> public SavedDataProvider() { } /// <summary> /// Deserialization constructor /// </summary> /// <param name="info">Serialization info</param> /// <param name="context">Streaming context</param> protected SavedDataProvider(SerializationInfo info, StreamingContext context) { dataSet = info.Deserialize<DataSet>("DataSet"); } #endregion #region ISerializable Members /// <summary> /// ISerializable interface implementation /// </summary> /// <param name="info">Serialization info</param> /// <param name="context">Streaming context</param> public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.Serialize<DataSet>("DataSet", dataSet); } #endregion #region IDataSetProvider Members DataSet IDataSetProvider.DataSet { get { return dataSet; } } IDataSetFactory IDataSetProvider.Factory { get { return null; } set { } } event Action<DataSet> IDataSetProvider.Change { add { change += value; } remove { change -= value; } } #endregion #region Members /// <summary> /// Sets Data set /// </summary> /// <param name="dataSet"></param> public void Set(DataSet dataSet) { this.dataSet = dataSet; change(dataSet); } #endregion }
4.3 外部数据集
数据集可以从不同来源获取。例如,数据集可以从 NASA/IPAC 银河系外数据库获取。我为此目的开发了 ExternalDataSetProvider
类。
/// <summary> /// External data set provider /// </summary> [Serializable()] public class ExternalDataSetProvider : SavedDataProvider, IChildrenObject { #region Fields /// <summary> /// Factory of data set /// </summary> IDataSetPoviderFactory factory; /// <summary> /// Type name of factory /// </summary> string factoryType; /// <summary> /// Url /// </summary> string url = ""; IAssociatedObject[] children = new IAssociatedObject[1]; #endregion #region Ctor /// <summary> /// Constructor from type of child object /// </summary> /// <param name="factoryType">Type of factory</param> public ExternalDataSetProvider(string factoryType) { this.factoryType = factoryType; CreateFactory(); } /// <summary> /// Deserialization constructor /// </summary> /// <param name="info">Serialization info</param> /// <param name="context">Streaming context</param> protected ExternalDataSetProvider(SerializationInfo info, StreamingContext context) : base(info, context) { factoryType = info.GetString("Factory"); url = info.GetString("Url"); CreateFactory(); } #endregion #region ISerializable Members /// <summary> /// ISerializable interface implementation /// </summary> /// <param name="info">Serialization info</param> /// <param name="context">Streaming context</param> public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("Factory", factoryType); info.AddValue("Url", url); } #endregion #region IChildrenObject Members IAssociatedObject[] IChildrenObject.Children { get { return children; } } #endregion #region Private Members /// <summary> /// Creates factory /// </summary> void CreateFactory() { Type t = Type.GetType(factoryType); if (t != null) { // Constructor of child object ConstructorInfo c = t.GetConstructor(new Type[0]); factory = c.Invoke(new object[0]) as IDataSetPoviderFactory; dataSet = factory.GetData(this.url); factory.Change += (string url) => { if (this.url.Equals(url)) { return; } this.url = url; dataSet = factory.GetData(url); change(dataSet); }; children[0] = factory as IAssociatedObject; } } #endregion
上面的代码需要一些注释。该类包含一个 IDataSetPoviderFactory
类型的子对象 factory
。子对象与其父对象一起被序列化。它通过其类型名称创建。以下代码代表 IDataSetPoviderFactory
类型。
/// <summary> /// Factory of data set provider /// </summary> public interface IDataSetPoviderFactory { /// <summary> /// Name /// </summary> string Name { get; } /// <summary> /// Gets data /// </summary> /// <param name="url">Url</param> /// <returns>Data</returns> DataSet GetData(string url); /// <summary> /// Change event /// </summary> event Action<string> Change; }
此类型的对象提供必要的数据集。以下代码提供了此接口的实现。
namespace Nasa.Ipac.Extragalactic { /// <summary> /// Data Provider /// </summary> [Diagram.UI.Attributes.Url("http://ned.ipac.caltech.edu/forms/nearposn.html")] public class DataProvider : CategoryObject, IDataSetPoviderFactory, IUrlConsumer, IUrlProvider { #region Fields private event Action<string> changeData = (string url) => { }; private DataSet dataSet = new DataSet(); private string url = ""; private Action<string> changeUrlConsumer = (string url) => { }; private Action<string> changeUrlProvider = (string url) => { }; #endregion #region IDataSetPoviderFactory Members string IDataSetPoviderFactory.Name { get { return "NASA/IPAC Extragalactic Database"; } } DataSet IDataSetPoviderFactory.GetData(string url) { UpdateData(url); return dataSet; } event Action<string> IDataSetPoviderFactory.Change { add { changeData += value; } remove { changeData -= value; } } #endregion #region IUrlConsumer Members string IUrlConsumer.Url { set { UpdateData(value); } } event Action<string> IUrlConsumer.Change { add { changeUrlConsumer += value; } remove { changeUrlConsumer -= value; } } #endregion #region IUrlProvider Members string IUrlProvider.Url { get { return url; } } event Action<string> IUrlProvider.Change { add { changeUrlProvider += value; } remove { changeUrlProvider -= value; } } #endregion #region Private Members void UpdateData(string url) { if (url == null) { return; } if (!url.Equals(this.url)) { DataTable dt = url.GetDataTable(); this.url = url; dataSet = new DataSet(); dataSet.Tables.AddRange(new DataTable[] { dt }); changeData(url); } } #endregion } } namespace Nasa.Ipac.Extragalactic.Data { /// <summary> /// Gets data from NASA Astrogalactic website /// </summary> public static class StaticExtensionNasaIpacExtragalacticData { #region Public Members /// <summary> /// Gets data table from http://ned.ipac.caltech.edu/forms/nearposn.html /// </summary> /// <param name="url">Url</param> /// <returns>Data Table</returns> static public DataTable GetDataTable(this string url) { DataTable table = new DataTable(); lock (ob) { /// Web request WebRequest req = WebRequest.Create(url); WebResponse resp = req.GetResponse(); List<string> l = new List<string>(); // reads data using (TextReader reader = new StreamReader(resp.GetResponseStream())) { return reader.GetDataTable(); } } } /// <summary> /// Gets data table from reader /// </summary> /// <param name="reader">Reader</param> /// <returns>Data table</returns> public static DataTable GetDataTable(this TextReader reader) { // Full code is contained in the source file } #endregion } }
下图解释了与 NASA/IPAC 银河系外数据库的互操作性
4 插件的使用
4.1 业务逻辑
很明显,NASA/IPAC 银河系外数据库是一个非常特殊的组件。因此,它应该实现为 插件。我的软件的所有插件都已在 XML 文件中描述。
<?xml version="1.0" encoding="utf-8" ?> <Root> <Assemblies> <Assembly file="Nasa.Ipac.Extragalactic.Data.dll"/> <Assembly file="Nasa.Ipac.Extragalactic.dll"/> </Assemblies> <Page pageName="Web databases" pageHint="Databaes obtained by Web"> <Object icon="Containers\NED.ico" type="DataSetService.ExternalDataSetProvider,DataSetService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" param="Nasa.Ipac.Extragalactic.DataProvider,Nasa.Ipac.Extragalactic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" hint="Extragalactic" arrow="false" /> </Page> </Root>
上面的 XML 意味着应用程序应该加载以下附加库
Nasa.Ipac.Extragalactic.Data.dll
Nasa.Ipac.Extragalactic.dll
Page
标签负责以下选项卡页面。
Object
标签负责一个按钮。icon
属性对应按钮的图标,type
属性对应对象的类型。param
属性对应一种对象类型。此类型的含义取决于上下文。此属性可由 反射 使用,如下所示。
if (kind.Length > 0) // Kind or additional parameter { // Searches constructor from string ConstructorInfo ci = t.GetConstructor(new System.Type[] { typeof(string) }); if (ci != null) { // Creates an object ICategoryObject ob = ci.Invoke(new object[] { kind }) as ICategoryObject; return ob; // returns the object } }
ExternalDataSetProvider
具有以下字符串构造函数
/// <summary> /// Constructor from type of child object /// </summary> /// <param name="factoryType">Type of factory</param> public ExternalDataSetProvider(string factoryType) { this.factoryType = factoryType; Type t = Type.GetType(factoryType); if (t != null) { // Constructor of child object ConstructorInfo c = t.GetConstructor(new Type[0]); factory = c.Invoke(new object[0]) as IDataSetPoviderFactory; } }
因此,以下 XML 代码
<Object type="DataSetService.ExternalDataSetProvider,DataSetService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" param="Nasa.Ipac.Extragalactic.DataProvider,Nasa.Ipac.Extragalactic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
意味着以下 C# 代码
new DataSetService.ExternalDataSetProvider(new Nasa.Ipac.Extragalactic.DataProvider())
但是,还有其他类型的含义,例如,如下所示。
/// <summary> /// Creates object the corresponds to button /// </summary> /// <param name="button">The button</param> /// <returns>Created object</returns> public override ICategoryObject CreateObject(IPaletteButton button) { string kind = button.Kind; // Kind of the object Type type = button.ReflectionType; if (type.IsSubclassOf(typeof(Camera))) { return factory.NewCamera(); } if (type.Equals(typeof(Motion6D.SerializablePosition))) { object ob = factory.CreateObject(kind); // Usage of the kind if (ob != null) { SerializablePosition pos = new SerializablePosition(); pos.Parameters = ob; if (ob is IPositionObject) { IPositionObject po = ob as IPositionObject; po.Position = pos; } return pos; } } return null; }
4.2 功能的自动扩展
如果您的计算机上安装了 Oracle 客户端,并且您想在我的框架中使用它。您只需将 OracleTableProvider.dll
放在应用程序目录中。排除 OracleTableProvider.dll
只会减少功能。以下函数搜索所有实现 IDataSetFactory
接口的对象
/// <summary> /// Initialization of database drivers /// </summary> /// <param name="path">Path of drivers</param> void Initialize(string path) { // Gets all database drivers from this directory IEnumerable<IDataSetFactory> en = path.GetInterfaces<IDataSetFactory>(); List<string> l = new List<string>(); foreach (IDataSetFactory f in en) { factories[f.FactoryName] = f; // Dictinary of drivers } List<string> ln = new List<string>(factories.Keys); ln.Sort(); names = ln.ToArray(); // Ordered names of drivers }
其中 GetInterfaces
如下所示。
/// <summary> /// Gets interfaces /// </summary> /// <typeparam name="T">Interface type</typeparam> /// <param name="directory">Directory</param> /// <returns>Interface objects</returns> public static IEnumerable<T> GetInterfaces<T>(this string directory) where T : class { string[] fn = Directory.GetFiles(directory, "*.dll"); // Dll files Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); // Current domain assemblies List<string> l = new List<string>(); foreach (Assembly a in ass) // Looking for objects in loaded assemblies { l.Add(a.Location); IEnumerable<T> en = a.GetInterfaces<T>(); foreach (T t in en) { yield return t; } } foreach (string f in fn) // Looking for objects in directory { if (!l.Contains(f)) { IEnumerable<T> en = Assembly.LoadFile(f).GetInterfaces<T>(); foreach (T t in en) { yield return t; } } } } /// <summary> /// Gets interfaces from assembly (Searching of driver assembly) /// </summary> /// <typeparam name="T">Interface type</typeparam> /// <param name="assembly">Assembly</param> /// <returns>Interface objects</returns> public static IEnumerable<T> GetInterfaces<T>(this Assembly assembly) where T : class { Type[] types = new Type[0]; try { types = assembly.GetTypes(); // Assembly types } catch (Exception) { } string st = typeof(T).FullName; // Interface full name foreach (Type t in types) { Type ti = t.GetInterface(st); // Gets interface if (ti == null) { continue; } FieldInfo fi = t.GetField("Singleton"); // Gets Singleton field if (fi != null) { yield return fi.GetValue(null) as T; // yeild Singleton } } }
4.3 用户界面
尽管我的框架不知道 Nasa.Ipac.Extragalactic.DataProvider
类型,但我的框架提供了该对象的属性编辑器。用户界面包含两个选项卡页面。
Data table 页面对应 ExternalDataSetProvider
类型的父对象。Data source 页面对应以下类的两个子对象。
namespace Nasa.Ipac.Extragalactic { ////// Data Provider /// [Diagram.UI.Attributes.Url("http://ned.ipac.caltech.edu/forms/nearposn.html")] // Initial url public class DataProvider : CategoryObject, IDataSetPoviderFactory, IUrlConsumer, IUrlProvider { // Implemetation ... }
[Diagram.UI.Attributes.Url("http://ned.ipac.caltech.edu/forms/nearposn.html")]
负责 Search 选项卡页面,IUrlConsumer
、IUrlProvider
接口负责 Result 选项卡页面。
第一个页面负责常量 URL,第二个页面对应更改的 URL。以下代码代表子用户界面的创建。
// Searching of additional control object o = factory.GetAdditionalFeature<IUrlConsumer>(provider as IAssociatedObject); if (o is Control) // Additional control { form = new FormExternalData(this.GetRootLabel(), o as Control); return; }
o
对象用作 FormExternalData
上的子选项卡页面。GetAdditionalFeature
函数如下所示。
/// <summary> /// Gets additional feature /// </summary> /// <typeparam name="T">Feature type</typeparam> /// <param name="factory">User interface factory</param> /// <param name="obj">Obj</param> /// <returns>Feature</returns> static public object GetAdditionalFeature<T>(this IUIFactory factory, IAssociatedObject obj) { IUIFactory f = factory; IUIFactory p = factory.Parent; if (p != null) { f = p; } if (obj == null) { return null; } if (obj is T) { return f.GetAdditionalFeature<T>((T)obj); } if (obj is IChildrenObject) // If object has children { IAssociatedObject[] ao = (obj as IChildrenObject).Children; foreach (IAssociatedObject aa in ao) // Searches additional feature among children { object ob = GetAdditionalFeature<T>(f, aa); if (ob != null) { return ob; } } } return null; }
以下代码代表 IUIFactory
接口实现的 GetAdditionalFeature
。
/// <summary> /// Gets additional feature /// </summary> /// <typeparam name="T">Feature type</typeparam> /// <param name="obj">Object</param> /// <returns>Feature</returns> public override object GetAdditionalFeature<T>(T obj) { if (!typeof(T).Equals(typeof(IUrlConsumer))) { return null; } IUrlConsumer c = obj as IUrlConsumer; UserControls.UserControlUrl uc = new UserControls.UserControlUrl(); if (c is IUrlProvider) { uc.Set(c as IUrlProvider); } uc.Set(c); return uc; }
上面的代码意味着如果子对象实现了 IUrlConsumer
接口,则编辑器表单将包含一个 UserControlUrl
类型的控件。因此,用户界面是从接口自动构建的。
5. 低内聚
我的软件包含很多库。然而,这一事实促进了 低内聚,这一事实带来了很多好处。例如,Nasa.Ipac.Extragalactic.Data.dll
提供了数据集的创建,但这个库与我的框架完全独立。因此,这个库可以很容易地集成到其他应用程序中。Nasa.Ipac.Extragalactic.dll
是 Nasa.Ipac.Extragalactic.Data.dll
和我的框架之间的桥梁。内聚有许多级别。例如,在 我的一项项目 中,我使用了 地球大气从地面到太空的经验性全局模型 (NRLMSISE-00) 源代码。这段代码不是面向对象的。我开发了一个面向对象的包装器,因为我想同时使用多个大气计算副本。下表代表了 5 个内聚级别。
信号强度 | 名称 | 依赖项 | 功能 | 用法 |
1 | Msise C++ 类 | 否 | 大气参数的计算 | 任何支持 C++ 的平台 |
2 | MSISEAtmosphere.dll 管理的 C++ 项目 | .NET | .NET 包装器(桥梁),用于 Msise | 任何支持 .NET 的平台 |
3 | DynamicAtmosphere.MSISE.dll C# 项目 | .NET,BaseTypes.dll | 先前项目的包装器,支持不同的 物理单位 | 任何支持 .NET 的平台 |
4 | DynamicAtmosphere.MSISE.Wrapper.dll C# 项目 | .NET,我的框架 | 我的框架与大气计算之间的桥梁 | 我的框架 |
5 | DynamicAtmosphere.MSISE.Wrapper.UI.dll C# 项目 | .NET,System.Windows.Forms,我的框架 | System.Windows.Forms 用户界面,用于大气计算 | 我的框架配备了 System.Windows.Forms 用户界面 |
您可以从我的 文章 下载此代码。
6 数据集消费者
6.1 数据集的统计选择
在我之前的文章中,我考虑了 统计学。数据集可以用作 统计数据集。我的软件使用两种统计分析方案,如下所述。
6.1.1 加载完整选择
此方案意味着一次性加载选择。
处理器将 **计算出的参数** 与 **选择** 进行比较,计算残差,然后校正 **回归参数**。以下示例显示了数据集在非线性回归中的应用。
Data 是 StatementWrapper
类型的对象,它实现了 IDataSetProvider
接口并封装了 SQL 查询。Data 的属性如下所示。
此对象使用 SQL Server 并执行以下查询
SELECT x.x, y.y, z.z, f1.f1, f2.f2 FROM f1, f2, x, y, z WHERE x.Id = f1.Idx AND y.Id = f1.Idy AND z.Id = f1.Idz AND f1.Idx = f2.Idx AND f1.Idy = f2.Idy AND f1.Idz = f2.Idz
结果是它提供了一个数据集。SQL Server 数据集可以被 Oracle 数据集替换,如 上面 所示。DS 链接将 IDataSetProvider
与 IDataSetConsumer
关联起来。Selection 是 DataSetSelection
类型的对象。此类型也实现了 IMeasurements
和 IStructuredSelectionCollection
。IMeasurements
是 信息流 的接口。Selection 对象的输出对应于数据表列。
该表包含 1000 行,所有 5 列均为 **Double** 类型,因此 **Selection** 返回五个 Double[1000]
“类型”的对象。这些对象被 **Formula** 使用。
Formula 对象执行向量函数的 分量式 计算。IStructuredSelectionCollection
是 统计领域 的接口。Selection 对象提供 5 个统计选择,对应于数据表的 5 列。Stat 箭头是 SelectionLink
类型的对象,此处 描述了该对象。箭头对应于统计领域。Regression 对象的属性如下所示。
这些属性具有以下含义。我们想找到 **Formula** 中 a、b、c、d、g 的值,使得 Formula_1、Formula_2 分别逼近选择 Table_f1 和 Table_f2。下图代表了逼近前后的参数值。
6.1.2 迭代方案
有时,前一种方案需要巨大的 随机存取存储器,因为它会同时加载所有数据。迭代方案分步迭代加载参数。
迭代器提供数据选择。y 是拟合方程的 **左侧**。**Transformation** 对应于非线性函数 f,并生成拟合模型的 **左侧**。**Processor** 协调所有操作并校正 **Regression parameters**。下图代表了这个模型。
Data 对象与 6.1.1 中的相同,Iterator 是以下 DataSetIterator
类型。
/// <summary> /// Iterator obtained from data set /// </summary> [Serializable()] public class DataSetIterator : CategoryObject, ISerializable, IIterator, IDataSetConsumer, IMeasurements { // Code is contained in the source file }
此类型实现 IIterator
接口。
/// <summary> /// Iterator /// </summary> public interface IIterator { /// <summary> /// Resets itself /// </summary> void Reset(); /// <summary> /// Go to next and false otherwise /// </summary> /// <returns>True if has next and</returns> bool Next(); }
该接口的实现如下所示。
/// <summary> /// Reference to a table row /// </summary> protected DataRow[] rowreference = new DataRow[] { null }; #region IIterator Members void IIterator.Reset() { current = 0; rowm[0] = table.Rows[0]; } bool IIterator.Next() { if (table == null) { return false; } ++current; if (current >= table.Rows.Count) { return false; } row = table.Rows[current]; rowreference[0] = row; return true; } #endregion
因此,该类逐行迭代数据表,并引用不同的行。行的引用实现为数组(此处)。引用用于通过以下方式实现 IMeasure
接口。
/// <summary> /// Measurement from data row /// </summary> class RowMeasure : IMeasure { string name; object type; DataRow[] row; int ordinal; Func<object> par; internal RowMeasure(string name, object type, DataRow[] row, int ordinal) { this.name = name; this.type = type; this.row = row; this.ordinal = ordinal; par = Get; } #region IMeasure Members Func<object> IMeasure.Parameter { get { return par; } } string IMeasure.Name { get { return name; } } object IMeasure.Type { get { return type; } } #endregion #region Private Members object Get() { return row[0][ordinal]; } #endregion
上面的代码意味着行中的元素被用作测量值。Iterator 作为 IMeasurement
被 **Formula** 使用,**Formula** 的属性如下所示。
此示例的公式与 前一个示例的公式 一致,但参数类型不一致。这里 x、y 和 z 是 Double
类型的参数,在前一个示例中它们是 Double[1000]
“类型”的参数。因此,这些公式返回两个 Double
类型的参数,之前的公式返回两个 Double[1000]
“类型”的参数。**Processor** 对象的属性如下所示。
上图意味着我们想定义 Formula 中 a、b、c、d、d 的值,使得 Formula_1(或 Formula 的 Formula_2)逼近 Iterator 的参数 f1(或 f2)。结果与 前一个示例 的结果一致,但它不需要大量的 随机存取存储器。
6.2 2D 图表
下图包含赫罗图,取自 http://www.astro.uni-bonn.de/~deboer/sterne/hrdtxt.html 。
上图与我的框架提供的图类似。
Data 执行到 Hipparcos 数据库的 SQL 查询。
Formula 提供必要的计算,特别是它计算恒星的 绝对星等。Color 是 DrawSeries
类型的对象。Color 的属性如下所示。
这意味着 2D 指示的 X、Y 坐标分别对应于 **Formula** 的 Formula_2、Formula_1。指示点的颜色和大小由 **Formula** 的 Forlula_3、...、Forlula_6 定义。数据库可以被替换为 Internet 数据,下图显示了 NASA/IPAC 银河系外数据库的应用。
但是,如果数据表包含大量行,则 Internet 数据库的应用会变得有问题。2D 指示图可以扩展如下。
现在我们除了指示外还有回归。Filer 是 FormulaFilterIterator
类的对象,它实现了 IIterator
。该对象用于数据过滤。该对象的属性如下。
过滤器条件是以下 3 个条件的 逻辑合取
- x>ay 表示视差误差超过视差误差的三倍;
- z< b 表示视差不超过 b(b=1000);
- |c + v - kz|< d 表示对象属于允许域,如下所示。
属于允许域的恒星被近似为 3 次多项式,如下所示。
Regression 提供必要的公式。
6.3 3D 图表 + 6D 运动学
下图配有电影,显示了具有 6D 运动学的 3D 图表。
Stars 是 PositionCollectionData
类型的对象,该对象的属性如下所示。
这些属性与 2D 图表的属性 类似。其他组件提供以下操作。
6.4 数据库 + 数字图像处理 + 统计。
在我以前的文章中,我描述了 将 2D 图像用作统计数据集 的应用。与此数据集和数据库数据集的比较使我们能够估计物理参数。下图解释了这个样本。
此样本可用于 导航。任务算法如下。
此方案的左侧包含图像处理。右侧代表星表的使用。桥梁比较两者,结果是我们获得了航天器姿态参数。让我们详细考虑。
6.4.1 图像处理
假设设备提供以下天体图像。
该图像包含干扰信息。我们需要进行过滤以排除它。非局部数字图像处理用于此目的。处理方案如下。
该方案包含设备提供的 **初始图像**(源图像)。小的正方形提供了必要的数学运算。结果是我们得到了 **过滤后的图像**(过滤结果)。两张图片如下。
下图解释了过滤算法。
如果我们有 9 个连续的白色像素,我们将用一个黑色像素替换它们。所有其他像素都是白色的。过滤结果使我们能够获得黑色像素的 X 和 Y 坐标。然后将这些数字与星表进行比较。Stat 组件从 **Filtered image** 中提取这些数字。
6.4.2 数据库的应用
星表存储在数据库中。可以通过 SQL 查询提取必要的信息。
查询语句如下。
++++++++++++++
SELECT RAdeg, DEdeg FROM hip_main WHERE RAdeg > @RAMIN AND RAdeg < @RAMAX AND DEdeg > @DEMIN AND DEDeg < @DEMAX AND BTmag > @BTMIN ORDER BY RAdeg
++++++++++++++
此语句的含义如下。首先,我们考虑一个有限的天空区域。 赤纬 和 赤经 属于小区间。其次,我们只考虑那些 星等 超过给定常数的恒星(在本例中,常数为 9)。查询结果提供了以下图表。
我们想将此图表与过滤后的图像进行比较。此操作需要一组数学变换。完整变换方案如下。
这些变换的基本特征是欧几里得变换。
参数 a、b 和 是未知的。比较星表和过滤后的图像可以帮助我们确定这些参数。使用这些参数,我们可以确定航天器的姿态。