“业务层”的设计模式 [英] design pattern of "Business Layer"

查看:91
本文介绍了“业务层”的设计模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想弄清楚哪种方法更好用。

让我解释一下这个场景。

我使用的是Nortwind。数据库。在这个数据库中,我有客户

表。以下是处理此表的两种不同方式。


案例1:

创建一个用于封装表Customers的结构。列

public struct structCustomers

{

public string CustomerID;

public string CompanyName;

public string ContactName;

public string ContactTitle;

public string Address;

public string City;

public string Region;

public string PostalCode;

public string Country;

public string Phone;

public string Fax;

public Customers(int i){

//将变量分配给它们的默认值

CustomerID = -1; CompanyName ="";

}

}

写一个包装表的类

公共类客户{

//与表存储过程相关的所有方法

public SqlDataReader GetAllCustomers()

{

.....

返回sqlcommand.executereader(" GetCustomers",.....)

}

}


如果需要将参数传递给方法我使用以下内容,

可以说是插图

public SqlDataReader InsertCustomerDetails( structCustomers sc)

{

sqlparameter customerid = new sqlparameter(" @ custid",

Sqldbtype.varchar)

customerid.Value = sc.CustomerID;

.....

返回sqlcommand.executereader(" GetCustomers",.....)

}


最后从调用UI我有以下

void button1_click()

{

structCusto mers sc = new structCustomers(0);

sc.CustomerID = textbox1.text;

客户c =新客户();

数据集ds = c.GetCustomerDetail(sc);

}

案例2:


写一个包含所有表相关信息的类

公共类客户{


公共字符串m_CustomerID;

公共字符串m_CompanyName;

公共字符串m_ContactName;

public string m_ContactTitle;

public string m_Address;

public string m_City;

public string m_Region;

public string m_PostalCode;

public string m_Country;

public string m_Phone;

public string m_Fax;


//写完所有设置并获得

公共对象CustomerID {

set

{

m_CustomerID = value;

}

get

{

返回m_CustomerID;

}

}


//所有方法都重新计算关于表的存储过程

public SqlDataReader GetAllCustomers()

{

.....

返回sqlcommand.executereader(" GetCustomers",.....)

}

}


如果需要将参数传递给我正在使用以下方法的方法,

可以说是插图

public SqlDataReader InsertCustomerDetails()

{

sqlparameter customerid = new sqlparameter(" @ custid",

Sqldbtype.varchar)

customerid.Value = this.m_CustomerID;

.....

返回sqlcommand.executereader(" GetCustomers",.....)

}


,最后从调用UI我有以下

void button1_click()

{

客户c =新客户();

c.CustomerID = textbox1.text;

数据集ds = c.GetCustomerDetail();

}


这些是我所知道的不同方式。哪一个更好用?评论

是受欢迎的,而且很有价值。


不是:不同的方法有它们的缺点,所以不要太在意

。作为一个例子让居住在任何一个国家/地区的客户加拿大或

土耳其 ,无论如何也许保持这种情况进一​​步讨论

解决方案

好问题,哈桑。


有一个这里涉及几个原则。一个是商务舱

应该关注自己的事业。也就是说,商业类应包含

无论使用哪种功能,并向可能需要它的任何客户类暴露可能需要的任何内容。第一个模型

不必要地将一个结构放入一个类中,该类包含处理结构所需的进程

。 外部是指外部。除了与客户课程合作的
之外,班级没有做任何事情。你称之为客户,但事实上,

代码用于与单个客户进行交换。一个类封装了数据和

进程,并且不需要一个类来包含数据,而另一个类需要包含该进程的
。显然,我们正在寻找一小部分客户和客户。可能会这样做,事实上,会涉及更多的过程。

例如,结构成员可以是使用

公共属性公开的私有字段。然后,这些公共属性可以包含用于验证等事务的
的过程。毕竟,CompanyName的数据库字段长度为

。例如,长度有限。如果输入的值太长,公共Setter可以

抛出异常。等等。这样,

客户类就可以自行管理。


所以,从某种意义上说,你的第二个模型更好。但是,我会用数据层进一步采取步骤

。考虑一下你的数据库函数:

//关于表的存储过程的所有方法
public SqlDataReader GetAllCustomers()
.....
.....
返回sqlcommand.executereader(" GetCustomers",.....)
}


和你的UI代码:

void button1_click()
{
structCustomers sc = new structCustomers(0);
sc.CustomerID = textbox1.text;
客户c =新客户() ;
dataset ds = c.GetCustomerDetail(sc);
}


首先,Customer类有成员公开数据库数据

面向对象的方式。该类代表客户。它是一个对象

代表一个实体,而不是一个代表任何事情的对象

与数据库。那么,为什么它暴露DataReader是有意义的,

特别是因为必须关闭DataReader,以及与它连接?


实际上,UI层甚至不应该意识到它正在使用

数据库。应该知道它正在使用Customer对象。如果

它需要CompanyName,它从

类的CompanyName属性获取它。等等,UI的工作是呈现客户。实体以用户友好的方式以用户友好的方式向用户提供。而商务舱的工作是以程序员友好的方式向UI和其他业务对象提供客户
数据。


所以,首先,客户类,以介意自己的业务,应该

只向客户公开与客户有关的字段和属性

类。


但还有更多。在那个数据库函数中,我抽象地看到的是一个

函数,它执行查询或存储过程,并返回一个

SqlDataReader。对我来说听起来像是一个潜在的可重复使用的函数,只需稍微调整一下就可以了。如下一个带有静态函数的Data类怎么样?


public static SqlDataReader GetDataReader(SqlConnection conn,

SqlCommand命令,字符串ProcedureName,

ParamArray params)

{

OpenConn(conn,command);

.. ...

返回lcommand.ExecuteReader(ProcedureName,params);

}


只是一个粗略的想法。你必须自己充实细节,

课程,包括如何处理ConnectionString等。


现在,Customer类是唯一的可能会使用此类

存储过程的类,因此它将知道过程名称和所需的参数

。因此,您有一个方法可以从Stored

过程填充类,例如Constructor方法。示例:


公共客户(字符串CustomerID)

{

尝试

{

SqlCommand命令;

SqlConnection conn;

SqlDataReader dr;

ParamArray params = ...;

dr = DataClass.GetDataReader(conn,command," GetCustomer",params);

...

_CustomerID = dr.GetString(dr.GetOrdinal( CustomerID));

...

}

catch(例外情况)

{。 ..}

终于

{

dr.Close();

DataClass.CloseConn(conn,command );

}

}


现在DataClass类封装了数据库功能,并且

Customer类封装了使用简单API创建Customer

所需的所有过程。任何UI类都可以通过传递ID来简单地创建一个客户实例



这就是面向对象的力量!


-

HTH,


Kevin Spencer

Microsoft MVP

..Net开发人员

歧义具有一定的品质。


Hasan O. Zavalsiz <豪******** @ gmail.com>在消息中写道

新闻:%2 **************** @ TK2MSFTNGP09.phx.gbl ...我想弄清楚哪种方法最好使用。
让我解释一下这个场景。
我使用的是Nortwind。数据库。在这个数据库中,我有客户表。以下是处理此表的两种不同方法。

案例1:
创建一个包装表的结构;客户和QUOT;列
公共结构structCustomers
公共字符串CustomerID;
公共字符串CompanyName;
公共字符串ContactName;
公共字符串ContactTitle;
公共string地址;
公共字符串城市;
公共字符串Region;
public string PostalCode;
public string Country;
public string Phone;
public string Fax ;
公共客户(int i){
//将变量分配给它们的默认值
CustomerID = -1; CompanyName ="";
}
}并编写一个包装表的类
公共类客户{
//与表存储过程相关的所有方法
public SqlDataReader GetAllCustomers()
{
.....
返回sqlcommand.executereader(" GetCustomers",.....)
}如果需要将参数传递给方法我使用以下内容,
可以说是插图
public SqlDataReader InsertCustomerDetails(structCustomers sc)
{
sqlparameter customerid = new sqlparameter(" @ custid",
Sqldbtype.varchar)
customerid.Value = sc.CustomerID;
..... 返回sqlcommand.executereader(" GetCustomers",.....)

最后从调用UI我有以下
void button1_click()
{
structCustomers sc = new structCustomers(0);
sc.CustomerID = textbox1.text;
Cust omers c = new Customers();
dataset ds = c.GetCustomerDetail(sc);
}

案例2:

写一个类包含所有与表相关的信息
公共类客户{

public string m_CustomerID;
public string m_CompanyName;
public string m_ContactName;
public string m_ContactTitle;
public string m_Address;
public string m_City;
public string m_Region;
public string m_PostalCode;
public string m_Country;
public string m_Phone;
public string m_Fax;

//写完所有设置并获取
公共对象CustomerID {
设置
{
m_CustomerID = value;
}
获取
{
返回m_CustomerID;
}
}
//所有与存储过程相关的方法关于表
public SqlDataReader GetAllCustomers()
{
.....
返回sqlcommand.executereader(" GetCustomers",.....)
}
}

如果一个eed将参数传递给我正在使用以下的方法,
让我们说一下插图
public SqlDataReader InsertCustomerDetails()
{sqlparameter customerid = new sqlparameter(" @custid" ;,
Sqldbtype.varchar)
customerid.Value = this.m_CustomerID;
.....
返回sqlcommand.executereader(" GetCustomers",..... )
}

最后从调用UI我有以下
void button1_click()
{
客户c =新客户();
c.CustomerID = textbox1.text;
dataset ds = c.GetCustomerDetail();
}
这些是我所知道的不同方式。哪一个更好用?
评论
是受欢迎的,也很有价值。

不是:不同的方法有它们的缺点,不关心这么多。一个例子让生活在加拿大或土耳其的国家/地区的客户满意。 ,无论如何也许保持这种情况进一​​步讨论



你好Hasan,


我更喜欢第二种方法。由于第一个是结构和

他们有限制。但最好的方法是将混合

方法封装在类中的结构。


这意味着

class x

{

结构客户

{

字符串客户;

}


}

并使用属性设置结构。

-------

问候,

C#,VB.NET,SQL SERVER,UML,DESIGN模式面试问题书
http://www.geocities.com/dotnetinterviews/

我的面试问题博客
http://spaces.msn.com/members/dotnetinterviews/


" Hasan O. Zavalsiz" <豪******** @ gmail.com> écritdansle message de news:

%2 **************** @ TK2MSFTNGP09.phx.gbl ...

|我想弄清楚哪种方法更好用。

|让我解释一下这个场景。

|我使用的是Nortwind。数据库。在这个数据库中我有客户

| table。以下是处理此表的两种不同方法。


基于表建模类永远不会像建模那样好主意

your class然后提供一个表来保存

该类实例的数据。


在示例Customer表中,联系人详细信息与

客户(公司)详情;这是第一个严重正常化的指标

表不是精心设计的课程的良好起点(公司

可以有多个联系人)


良好的OO实践建议您将业务逻辑从数据层中完全分离出来,这样您就可以开始使用Contact类:


公共界面IIdentifiable

{

int ID {get,set};

}


开始时将身份的概念与其他任何东西分开,在

之后,你不应该在数据库中使用除整数之外的任何东西作为主要的
键表也​​不应该有任何商业意义。现在一个

客户可能有一个可能是字母数字的参考代码,但是除了用于数据库密钥的任何唯一整数之外,还有一个



公共课程联系方式:IIdentifiable

{

private int id;

私人字符串名称;

私人字符串标题;


int IIdentifiable.ID

{

get {return id; }

set {id = value; }

}


公共字符串名称

{

get {return name; }

set {name = value; }

}


公共字符串标题

{

get {return title; }

set {title = value; }

}

}


请注意,Contact类中的id字段是一个整数,它不是

作为公共财产浮出水面,而只能通过IIdentifiable接口从外部访问

。这是在日常代码中使用

ID的一种威慑,因为只有存储和检索Contact类实例的持久性

机制才真正需要它。对于每个联系人来说,你不太可能需要一个可读的参考代码,所以

已经从课堂上省略了。


Customer类是相似的,但是有一两个方面

会有所不同,包括Contact类和normal类。数据库表




公共类客户:IIdentifiable

{

private int id;

私人字符串引用;

私人字符串名称;

私人字符串地址;

私有字符串城市;

私人字符串区域;

私人字符串postalCode;

私人字符串国家/地区;

私人字符串电话;

私人字符串传真;


... //公共财产


private List< Contact>联系人;


public Enumerator< Contact>联系方式

{

get {return contacts.GetEnumerator(); }

}


public联系方式AddContact()

{

contacts.Add(new Contact ());

}


public void RemoveContact(联系联系人)

{

联系人。删除(联系);

}

}


可能需要包含一个Customer Ref属性,以便

字符串字段和属性将为此添加。


请注意,我们保持隐藏联系人列表并且只允许添加

或通过方法删除联系人;如果你需要联系人列表,那么

你只能得到一个内部列表的枚举器。


另请注意,我们没有外键联系

类中的客户,这对于关系数据库中的1-n关系是正常的。

而不是客户有一个联系人列表。


数据访问层的工作是将此对象转换为与bDB关系的
关系,但业务类需要知道

没有这个问题。


然后你会看一个数据访问层,它的工作就是采取任何支持IIdentifiable并使用反射的

对象持久化/检索

该特定对象的数据,使用隐藏和ID作为数据库

表主键或外键。


公共类ObjectStore

{

public bool StoreObject(IIdentifiable obj)

{

//从界面中提取ID,然后转换为Object并使用反射

// to提取属性值

//然后使用值创建一个SQL Insert或Update语句

}


...

}


就像你只想要从一个

数据库中返回一组记录一样,所以你永远不应该期望从Object

Store中检索对象,只返回一个对象。 ObjectStore类上的Retrieval方法

应返回一个List,然后您可以以正常方式遍历。 .NET

datagrids就像显示对象的属性一样,因为它们显示了表格的字段。


使用这种技术使您可以灵活地更改数据库

供应商,而无需更改任何业务编码;唯一的

更改将是生成的SQL和创建的查询组件

处理该SQL。


进一步阅读在OPF(对象持久性框架)上访问我的网站
www.carterconsulting.org.uk; 文章是为德尔福观众撰写的,

但原则是相同的。


Joanna


-

Joanna Carter [TeamB]

顾问软件工程师

Hi , i am trying to figure out which approach is better to use .
let me explain the scenario.
i am using the "Nortwind" database . in this database i have "Customers "
table .The following is the two different ways to handle this table.

CASE 1 :
create a struct that encaplusates table "Customers" columns
public struct structCustomers
{
public string CustomerID;
public string CompanyName;
public string ContactName;
public string ContactTitle;
public string Address;
public string City;
public string Region;
public string PostalCode;
public string Country;
public string Phone;
public string Fax;
public Customers(int i) {
// assign variables to their default whatever they are
CustomerID = -1 ; CompanyName ="";
}
}
And write a class that encaplusates table
public class Customers {
// all methods related to stored procedures about table
public SqlDataReader GetAllCustomers()
{
.....
return sqlcommand.executereader("GetCustomers",.....)
}
}

and if a need to pass parameters to a method i am using the following ,
lets say as an illustration
public SqlDataReader InsertCustomerDetails(structCustomers sc )
{
sqlparameter customerid = new sqlparameter ("@custid",
Sqldbtype.varchar)
customerid.Value = sc.CustomerID ;
.....
return sqlcommand.executereader("GetCustomers",.....)
}

and finally from calling UI i have the following
void button1_click()
{
structCustomers sc = new structCustomers(0);
sc.CustomerID = textbox1.text ;
Customers c = new Customers ();
dataset ds = c.GetCustomerDetail (sc);
}
CASE 2 :

write a class that encaplusates all table related info
public class Customers {

public string m_CustomerID;
public string m_CompanyName;
public string m_ContactName;
public string m_ContactTitle;
public string m_Address;
public string m_City;
public string m_Region;
public string m_PostalCode;
public string m_Country;
public string m_Phone;
public string m_Fax;

// write all set and get
public object CustomerID{
set
{
m_CustomerID= value;
}
get
{
return m_CustomerID;
}
}

// all methods related to stored procedures about table
public SqlDataReader GetAllCustomers()
{
.....
return sqlcommand.executereader("GetCustomers",.....)
}
}

and if a need to pass parameters to a method i am using the following ,
lets say as an illustration
public SqlDataReader InsertCustomerDetails()
{
sqlparameter customerid = new sqlparameter ("@custid",
Sqldbtype.varchar)
customerid.Value = this.m_CustomerID;
.....
return sqlcommand.executereader("GetCustomers",.....)
}

and finally from calling UI i have the following
void button1_click()
{
Customers c = new Customers ();
c.CustomerID = textbox1.text ;
dataset ds = c.GetCustomerDetail ();
}

these are the different ways i know. Which one is better to use ? Comments
are welcome , and valuable.

not : the different approaches has their disadvantages, dont care about so
much .as an example " get the customers who live either country "Canada" or
"Turkey" , anyway maybe keep this situation for further discussions

解决方案

Good question, Hassan.

There are a couple of principles involved here. One is that a business class
should "mind its own business." That is, a business class should contain
whatever functionality is necessary to work with it, and expose whatever may
be necessary to any client class that may need it. the first model
unnecessarily puts a structure into a class that contains the processes
needed to work on the structure. The "outer" class isn''t doing anything but
working with Customer classes. You call it "Customers," but in fact, the
code is for woking with a single "Customer." A class encapsulates data and
process, and there is no need for one class to contain the data, and another
to contain the process. Obviously, we''re looking at a thin slice of what a
"Customer" might do, and in fact, there would be much more process involved.
For example, the structure members could be private fields exposed using
public properties. These public properties could then contain process for
doing things like validation. After all, the length of the database field
for "CompanyName," for example, is limited in length. A public Setter could
throw an exception if the value input was too long. And so on. This way, the
Customer class would manage itself.

So, in a sense, your second model is better. However, I would take it a step
further, with a Data Layer. Consider your database function:

// all methods related to stored procedures about table
public SqlDataReader GetAllCustomers()
{
.....
return sqlcommand.executereader("GetCustomers",.....)
}
}
and your UI code:
void button1_click()
{
structCustomers sc = new structCustomers(0);
sc.CustomerID = textbox1.text ;
Customers c = new Customers ();
dataset ds = c.GetCustomerDetail (sc);
}
First, the Customer class has members which expose database data in an
object-oriented way. The class represents a "Customer." It is an object
which represents an entity, not an object which represents anything to do
with a database. So, why would it make sense for it to expose a DataReader,
especially since a DataReader must be closed, and the Connection with it?

In fact, the UI layer shouldn''t even be aware that it is working with a
database. It should be aware that it is working with a Customer object. If
it needs the CompanyName, it gets it from the CompanyName property of the
class. Etc. the UI''s job is to present a "Customer" entity to a user in a
user-friendly manner. And the business class''s job is to present Customer
data to the UI and other business objects in a programmer-friendly manner.

So, first, the Customer class, in order to "mind its own business," should
only expose fields and properties pertaining to a Customer to client
classes.

But there''s more. In that database function, what I see abstractly is a
function that executes a query or stored procedure, and returns a
SqlDataReader. Sounds like a potentially reusable function to me, with a
little tweaking. How about a Data class with a static function like the
following?

public static SqlDataReader GetDataReader(SqlConnection conn,
SqlCommand command, string ProcedureName,
ParamArray params)
{
OpenConn(conn, command);
.....
return lcommand.ExecuteReader(ProcedureName, params);
}

Just a rough idea. You would have to flesh out the details yourself, of
course, including how to handle the ConnectionString, etc.

Now, the Customer class is the only class that will probably using this
Stored Procedure, so it will know the Procedure name and the parameters
needed. So, you have a method that populates the class from the Stored
Procedure, such as a Constructor method. Example:

public Customer(string CustomerID)
{
try
{
SqlCommand command;
SqlConnection conn;
SqlDataReader dr;
ParamArray params = ...;
dr = DataClass.GetDataReader(conn, command, "GetCustomer", params);
...
_CustomerID = dr.GetString(dr.GetOrdinal("CustomerID"));
...
}
catch (Exception ex)
{...}
finally
{
dr.Close();
DataClass.CloseConn(conn, command);
}
}

Now the DataClass class encapsulates database functionality, and the
Customer class encapsulates all the process necessary to create a Customer
with a simple API. Any UI class can simply create an instance of a Customer
by passing the ID

That''s the power of object-orientation!

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
Ambiguity has a certain quality to it.

"Hasan O. Zavalsiz" <ho********@gmail.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl... Hi , i am trying to figure out which approach is better to use .
let me explain the scenario.
i am using the "Nortwind" database . in this database i have "Customers "
table .The following is the two different ways to handle this table.

CASE 1 :
create a struct that encaplusates table "Customers" columns
public struct structCustomers
{
public string CustomerID;
public string CompanyName;
public string ContactName;
public string ContactTitle;
public string Address;
public string City;
public string Region;
public string PostalCode;
public string Country;
public string Phone;
public string Fax;
public Customers(int i) {
// assign variables to their default whatever they are
CustomerID = -1 ; CompanyName ="";
}
}
And write a class that encaplusates table
public class Customers {
// all methods related to stored procedures about table
public SqlDataReader GetAllCustomers()
{
.....
return sqlcommand.executereader("GetCustomers",.....)
}
}

and if a need to pass parameters to a method i am using the following ,
lets say as an illustration
public SqlDataReader InsertCustomerDetails(structCustomers sc )
{
sqlparameter customerid = new sqlparameter ("@custid",
Sqldbtype.varchar)
customerid.Value = sc.CustomerID ;
.....
return sqlcommand.executereader("GetCustomers",.....)
}

and finally from calling UI i have the following
void button1_click()
{
structCustomers sc = new structCustomers(0);
sc.CustomerID = textbox1.text ;
Customers c = new Customers ();
dataset ds = c.GetCustomerDetail (sc);
}
CASE 2 :

write a class that encaplusates all table related info
public class Customers {

public string m_CustomerID;
public string m_CompanyName;
public string m_ContactName;
public string m_ContactTitle;
public string m_Address;
public string m_City;
public string m_Region;
public string m_PostalCode;
public string m_Country;
public string m_Phone;
public string m_Fax;

// write all set and get
public object CustomerID{
set
{
m_CustomerID= value;
}
get
{
return m_CustomerID;
}
}

// all methods related to stored procedures about table
public SqlDataReader GetAllCustomers()
{
.....
return sqlcommand.executereader("GetCustomers",.....)
}
}

and if a need to pass parameters to a method i am using the following ,
lets say as an illustration
public SqlDataReader InsertCustomerDetails()
{
sqlparameter customerid = new sqlparameter ("@custid",
Sqldbtype.varchar)
customerid.Value = this.m_CustomerID;
.....
return sqlcommand.executereader("GetCustomers",.....)
}

and finally from calling UI i have the following
void button1_click()
{
Customers c = new Customers ();
c.CustomerID = textbox1.text ;
dataset ds = c.GetCustomerDetail ();
}

these are the different ways i know. Which one is better to use ?
Comments
are welcome , and valuable.

not : the different approaches has their disadvantages, dont care about so
much .as an example " get the customers who live either country "Canada"
or
"Turkey" , anyway maybe keep this situation for further discussions



Hi Hasan,

I will prefer the second approach. As the first one is is structure and
they have there limitation. But the best approach would be the hybrid
approach encapsulate the structure inside the class.

Thats mean
class x
{
structure customer
{
string customer;
}

}
And use the properties to set the structure.
-------
Regards ,
C#, VB.NET , SQL SERVER , UML , DESIGN Patterns Interview question book
http://www.geocities.com/dotnetinterviews/
My Interview Questions Blog
http://spaces.msn.com/members/dotnetinterviews/


"Hasan O. Zavalsiz" <ho********@gmail.com> a écrit dans le message de news:
%2****************@TK2MSFTNGP09.phx.gbl...

| Hi , i am trying to figure out which approach is better to use .
| let me explain the scenario.
| i am using the "Nortwind" database . in this database i have "Customers "
| table .The following is the two different ways to handle this table.

Modelling a class based on a table is never as good an idea as modelling
your class and then providing a table to persist the data of instances of
that class.

In the example Customer table, the Contact details are mixed in with the
Customer(Company) details; this is the first indicator that badly normalised
tables are not a good starting point for well designed classes (a Company
can have more than one Contact)

Good OO practice suggests that you separate your business logic completely
from your data layer, so you could start by having a Contact class :

public interface IIdentifiable
{
int ID { get, set };
}

Start off by separating the concept of identity from anything else, after
all, you should not either use anything other than an integer for a primary
key in a database table nor should that key have any business meaning. Now a
Customer may well have a reference code that could be alphanumeric but that
would be in addition to any unique integer used for database keys.

public class Contact : IIdentifiable
{
private int id;
private string name;
private string title;

int IIdentifiable.ID
{
get { return id; }
set { id = value; }
}

public string Name
{
get { return name; }
set { name = value; }
}

public string Title
{
get { return title; }
set { title = value; }
}
}

Note that the id field in the Contact class is an integer and that it is not
surfaced as a public property, instead it can only be accessed from outside
the class through the IIdentifiable interface. This is a deterrent to using
the ID in everyday code as it will only really be wanted by the persistence
mechanism that stores and retrieves instances of your Contact class. It is
unlikely that you would need a readable reference code for each Contact, so
that has been omitted from the class.

The Customer class will be similar, but there are one or two aspects that
will differ, both from the Contact class and also a "normal" database table
:

public class Customer : IIdentifiable
{
private int id;
private string ref;
private string name;
private string address;
private string city;
private string region;
private string postalCode;
private string country;
private string phone;
private string fax;

... // public properties

private List<Contact> contacts;

public Enumerator<Contact> Contacts
{
get { return contacts.GetEnumerator(); }
}

public Contact AddContact()
{
contacts.Add(new Contact());
}

public void RemoveContact(Contact contact)
{
contacts.Remove(contact);
}
}

It would possibly be necessary to include a Customer Ref property so a
string field and property would be added for this.

Notice that we are keeping the Contacts list hidden and only allowing adding
or removing of Contacts via methods; if you need the list of Contacts, then
you can only get an enumerator to the internal list.

Also note that we don''t have a "foreign key" to the Customer in the Contact
class as would be normal for a 1-n relationship in a relational database.
Instead the Customer has a list of Contacts.

It would be the job of a data access layer to translate this object
relationship to the RDB relationship, but the business classes need know
nothing of this matter.

You would then look at a data access layer whose job it is to take any
object that supports IIdentifiable and use reflection to persist/retrieve
the data for that particular object, using the "hidden" ID as the database
table primary or foreign keys.

public class ObjectStore
{
public bool StoreObject(IIdentifiable obj)
{
// extract ID from the interface, then cast to Object and use reflection
// to extract the property values
// Then create a SQL Insert or Update statement using the values
}

...
}

Just as you would only ever expect a set of records to be returned from a
database, so you should never expect a retrieval of objects from an Object
Store to only return one object. A Retrieval method on the ObjectStore class
should return a List which you can then traverse in the normal manner. .NET
datagrids are just as capable of displaying properties of objects as they
are of displaying fields of tables.

Using this technique gives you the flexibility to change your database
vendor without having to change any of your business coding; the only
changes wouldf be to the SQL generated and the query component created to
handle that SQL.

For further reading on OPFs (Object Persistence Frameworks) go to my website
www.carterconsulting.org.uk; the articles are written for a Delphi audience,
but the principles are the same.

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer


这篇关于“业务层”的设计模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆