2010-06-03 7 views
2

필자는 n 계층 데이터 액세스를위한 새로운 패턴으로 놀아 왔으며 매우 유연하고 구현하기 쉬운 것으로 보이는 패턴을 발견했습니다. 기본적으로 DB에서 기본 데이터 액세스, 분산 캐싱, 로컬 캐싱 등 다양한 데이터 레이어를 즉석에서 다양한 데이터 레이어로 만들 수있는 솔루션이 필요했습니다.일반 다중 레이어 데이터 액세스 패턴?

아래의 코드는 쉽게 재사용되고 매우 효율적입니다. 이전에 전적으로 하드 코딩 된 솔루션보다 몇 시간 이상 오래 걸립니다.

어떻게 보이나요? 이것이 더 잘 구현 될 수있는 방법이 있습니까? 어떤 일반적인 생각이나 비판? 유사한 패턴을 사용한 사람들의 의견은 무엇입니까?

기본 클래스 :

public class DataAdapterFactory<T> where T : class { private DataAdapter<T> Adapter; public DataAdapterFactory(DataAdapterBase<T> Base) { Adapter = Base; } public void Extend<U>() where U : DataAdapterExtender<T>, T, new() { DataAdapterExtender<T> Extender = new U(); Extender.BaseAdapter = Adapter as T; Adapter = Extender; } public T GetAdapter() { return Adapter as T; } } public class DataAdapter<T> where T : class { } public class DataAdapterBase<T> : DataAdapter<T> where T : class { } public class DataAdapterExtender<T> : DataAdapter<T> where T : class { public T BaseAdapter; } 

는 DAL에서 구현 :

// base interface defines methods 
public interface IMyDataAdapter 
{ 
    string GetString(); 
} 
// base sql adapter 
public class SqlDataAdapter : DataAdapterBase<IMyDataAdapter>, IMyDataAdapter 
{ 
    public string GetString() 
    { 
     return "SQL"; 
    }  
} 
// provides cache support 
public class DistributedCacheExtender : DataAdapterExtender<IMyDataAdapter>, IMyDataAdapter 
{ 
    public string GetString() 
    { 
     return BaseAdapter.GetString() + ", Distributed Cache"; 
    } 
} 
// provides local cache support 
public class LocalCacheExtender : DataAdapterExtender<IMyDataAdapter>, IMyDataAdapter 
{ 
    public string GetString() 
    { 
     return BaseAdapter.GetString() + ", Local Cache"; 
    } 
} 

데이터 액세스 :

public IMyDataAdapter GetAdapter() 
{ 
    // create adapter based on SqlDataAdapter 
    DataAdapterFactory<IMyDataAdapter> factory = new DataAdapterFactory<IMyDataAdapter>(new SqlDataAdapter()); 
    // implement distributed cache 
    factory.Extend<DistributedCacheExtender>(); 
    // implement local cache 
    factory.Extend<LocalCacheExtender>(); 
    return factory.GetAdapter(); 
} 

사용 위의 팩토리, 기본 어댑터 및 Extender (확장 순서 <()를 실행 순서대로 호출해야 함)를 인터페이스를 통해 즉석에서 원활하게 사용할 수 있습니다. 비즈니스 계층은 구현에 대해 아무 것도 모릅니다.

위의 경우 GetString()을 호출하면 "SQL, 분산 캐시, 로컬 캐시"가됩니다. 실제 시나리오에서는 로컬 캐시가 먼저 호출됩니다. 항목이 없으면 분산 캐시로 넘어 가고 거기에 없으면 DB에서 가져옵니다. 모든 모듈은 obejct에 따라 필요할 때마다 바꿀 수 있습니다. , 사용자 등

답변

1
나는이에 대한 http://en.wikipedia.org/wiki/Decorator_pattern보고 싶은데

- 당신의 예는 다음과 같은 것이 될 것입니다 :

public interface IMyDataAdapter 
{ 
    string GetString(); 
} 

public class SqlDataAdapter : IMyDataAdapter 
{ 
    public string GetString() 
    { 
     return "SQL"; 
    }  
} 

public class LocalCacheDecorator : IMyDataAdapter 
{ 
    private IMyDataAdapter adapter; 
    public LocalCacheDecorator(IMyDataAdapter adapter) 
    { 
     this.adapter = adapter; 
    } 

    public string GetString() 
    { 
     return "Local cache, " + this.adapter.GetString(); 
    } 
} 
+0

확실히 옵션입니다. 당신이 새로운 '데코레이터'를 구현할 때마다 생성자를 작성해야 할 필요성이 있었지만, 나는 방금 nitpicky가 될 수 있습니다 ... – Andrew

+0

이 접근법은 상속에 비해 컴포지션을 선호하며 의존성 주입을 사용하면 잘 작동합니다. –

0

무엇이 도움이 될 것입니다하지만 당신이 합리적으로 재치있는 모습을하고있는 어떤 클래스가 네임 스페이스와 어셈블리와 관련되어 있는지 확인하십시오.

내 경험으로는 인터페이스 뒤에있는 데이터 공급자를 추상화하는 경험이 있습니다. 데이터 제공자 (때로는 인터페이스)는 별도의 어셈블리에 있습니다 (즉, BL의 경우 1, 인터페이스의 경우 1, 데이터 제공 업체마다 1).

데이터 소스 (예 : db 테이블)가 아닌 비즈니스 개념 (예 : IPageDataProvider, ICustomerDataProvider 등) 주변의 인터페이스를 정의하고 인터페이스를 디자인 할 때 Interface Segeration Principle을 염두에두고 싶습니다.

런타임을 통해 공장을 통해 원하는 데이터 공급자를로드합니다. 이 방법은 Activator.CreateInstance 방법을 사용합니다. 공장은 config로부터 지시를받습니다.

따라서 비즈니스 로직에서 데이터를 소비하려면 공장 (코드 한 줄)을 통해 원하는 인터페이스 구현의 인스턴스를 만듭니다.

이 접근법을 사용하면 제공자 이있는 기본 클래스는 없지만 원하는 경우 데이터 제공자 내에서 기본 클래스를 사용할 수 있습니다.

0

나는 당신의 목적을 만족시킬 수있는 일종의 하이브리드 추상 팩토리를 생각해 냈고 개발자들로부터 연결 세부 사항도 숨 깁니다. 우리는 연결 세트를 제공합니다. 우리는 각 세트에 4 개가 필요했습니다. 이 4 개는 '연결 세트'팩토리에 의해 반환되며, 언제든지 반환되는 연결을 변경할 수있는 '사용자 지정 연결 세트 팩토리'도 있습니다. 프록시를 사용하여 연결 개체에 액세스합니다. 그런 다음 싱글 톤을 통해 프록시에 액세스합니다. 응용 프로그램로드 이벤트 또는 global.asmx에서 설정할 수 있습니다. 그런 다음 사용중인 연결을 스와핑하는 것은 매우 쉽습니다. 비록 당신이 런타임 주위에 스왑 수 있습니다. 희망이 도움이됩니다.

내 시나리오 용으로 특별히 작성되었으므로 다소 과장 될 수 있습니다.

이것은 npgsql 용이므로 표준 .data로 쉽게 변경할 수 있습니다. 클라이언트 기본 클래스 또는 sqlclent 클래스 ...

Public MustInherit Class DBConnectionDetail 
    'note this abstract class could be an interface if you didn't want these common methods 

    Protected _conStrBldr As New Npgsql.NpgsqlConnectionStringBuilder 
    Protected _connection As Npgsql.NpgsqlConnection 

    Public Sub New() 
     'Set the connection builder properties in the subclass 
    End Sub 

    Friend ReadOnly Property ConnectionStringBuilder() As Npgsql.NpgsqlConnectionStringBuilder 
     Get 
      Return _conStrBldr 
     End Get 
    End Property 


    Friend Property Connection() As Npgsql.NpgsqlConnection 
     Get 
      Return _connection 
     End Get 
     Set(ByVal value As Npgsql.NpgsqlConnection) 
      _connection = value 
     End Set 
    End Property 

    ' Misc properties - information for programmers of higher layers 
    Public MustOverride ReadOnly Property Description() As String 
    Public MustOverride ReadOnly Property HostName() As String 
    Public MustOverride ReadOnly Property IP() As String 
    Public MustOverride ReadOnly Property Database() As String 
End Class 



Public Class LocalArchiveConnectionDetails 
    Inherits DBConnectionDetail 


    Public Sub New() 
     _conStrBldr.Host = "localhost" 
     _conStrBldr.Port = 5432 
     _conStrBldr.UserName = "usr" 
     _conStrBldr.Password = "pwd" 
     _conStrBldr.Database = "archive" 
     '_conStrBldr.Pooling = True 
     '_conStrBldr.MinPoolSize = 5 
     '_conStrBldr.MaxPoolSize = 10 
     '_conStrBldr.CommandTimeout = 1024 
     '_conStrBldr.Timeout = 1024 
     '_conStrBldr.ConnectionLifeTime = 2 
    End Sub 


    Public Overrides ReadOnly Property Description() As String 
     Get 
      Return "Local Connection to Database" 
     End Get 
    End Property 

    Public Overrides ReadOnly Property Database() As String 
     Get 
      Return "archive" 
     End Get 
    End Property 

    Public Overrides ReadOnly Property HostName() As String 
     Get 
      Return "local host" 
     End Get 
    End Property 

    Public Overrides ReadOnly Property IP() As String 
     Get 
      Return "127.0.0.1" 
     End Get 
    End Property 
End Class 

Public Interface IConnectionFactory 

    ReadOnly Property GetMasterConnection() As DBConnectionDetail 
    ReadOnly Property GetWarehouseConnection() As DBConnectionDetail 
    ReadOnly Property GetArchiveConnection() As DBConnectionDetail 
    ReadOnly Property GetAuditConnection() As DBConnectionDetail 


End Interface 

    Public Class DBConnectionBuilder 

    Friend Shared Function GetConnection(ByVal conStrBldr As DBConnectionDetail) As NpgsqlConnection 
     Return New NpgsqlConnection(conStrBldr.ConnectionStringBuilder.ConnectionString) 
    End Function 

    'Friend Shared Function GetConnection(ByVal conStr As String) As NpgsqlConnection 
    ' Return New NpgsqlConnection(conStr) 
    'End Function 

End Class 

    Public Class LocalConnectionFactory 
    Implements IConnectionFactory 


    Public ReadOnly Property GetArchiveConnection() As DBConnectionDetail Implements IConnectionFactory.GetArchiveConnection 
     Get 
      Dim dbConnection As New LocalArchiveConnectionDetails 
      dbConnection.Connection = DBConnectionBuilder.GetConnection(dbConnection) 
      Return dbConnection 
     End Get 
    End Property 

    Public ReadOnly Property GetMasterConnection() As DBConnectionDetail Implements IConnectionFactory.GetMasterConnection 
     Get 
      Dim dbConnection As New LocalMasterConnectionDetails 
      dbConnection.Connection = DBConnectionBuilder.GetConnection(dbConnection) 
      Return dbConnection 
     End Get 
    End Property 

    Public ReadOnly Property GetWarehouseConnection() As DBConnectionDetail Implements IConnectionFactory.GetWarehouseConnection 
     Get 
      Dim dbConnection As New LocalWarehouseConnectionDetails 
      dbConnection.Connection = DBConnectionBuilder.GetConnection(dbConnection) 
      Return dbConnection 
     End Get 
    End Property 

    Public ReadOnly Property GetAuditConnection() As DBConnectionDetail Implements IConnectionFactory.GetAuditConnection 
     Get 
      Dim dbConnection As New LocalAuditConnectionDetails 
      dbConnection.Connection = DBConnectionBuilder.GetConnection(dbConnection) 
      Return dbConnection 
     End Get 
    End Property 
End Class 

''' <summary> 
''' The custom connection factory allows higher layers to decide which connection will be returned by the connection proxy 
''' </summary> 
''' <remarks></remarks> 
Public Class CustomConnectionFactory 
    Implements IConnectionFactory 

    Private _archiveConnection As DBConnectionDetail 
    Private _masterConnection As DBConnectionDetail 
    Private _warehouseConnection As DBConnectionDetail 
    Private _auditConnection As DBConnectionDetail 

    Friend Sub New() 

    End Sub 

    Friend Sub New(ByVal masterConnection As DBConnectionDetail, ByVal archiveConnection As DBConnectionDetail, _ 
        ByVal warehouseConnection As DBConnectionDetail, ByVal auditConnection As DBConnectionDetail) 
     _masterConnection = masterConnection 
     _archiveConnection = archiveConnection 
     _warehouseConnection = archiveConnection 
     _auditConnection = auditConnection 
    End Sub 

    Friend Sub SetMasterConnectionDetail(ByVal connectionDetail As DBConnectionDetail) 
     _masterConnection = connectionDetail 
    End Sub 
    Friend Sub SetArchiveConnectionDetail(ByVal connectionDetail As DBConnectionDetail) 
     _archiveConnection = connectionDetail 
    End Sub 
    Friend Sub SetWarehouseConnectionDetail(ByVal connectionDetail As DBConnectionDetail) 
     _warehouseConnection = connectionDetail 
    End Sub 
    Friend Sub SetAuditConnectionDetail(ByVal connectionDetail As DBConnectionDetail) 
     _auditConnection = connectionDetail 
    End Sub 

    Public ReadOnly Property GetArchiveConnection() As DBConnectionDetail Implements IConnectionFactory.GetArchiveConnection 
     Get 
      _archiveConnection.Connection = DBConnectionBuilder.GetConnection(_archiveConnection) 
      Return _archiveConnection 
     End Get 
    End Property 

    Public ReadOnly Property GetMasterConnection() As DBConnectionDetail Implements IConnectionFactory.GetMasterConnection 
     Get 
      _masterConnection.Connection = DBConnectionBuilder.GetConnection(_masterConnection) 
      Return _masterConnection 
     End Get 
    End Property 

    Public ReadOnly Property GetWarehouseConnection() As DBConnectionDetail Implements IConnectionFactory.GetWarehouseConnection 
     Get 
      _warehouseConnection.Connection = DBConnectionBuilder.GetConnection(_warehouseConnection) 
      Return _warehouseConnection 
     End Get 
    End Property 

    Public ReadOnly Property GetAuditConnection() As DBConnectionDetail Implements IConnectionFactory.GetAuditConnection 
     Get 
      _auditConnection.Connection = DBConnectionBuilder.GetConnection(_auditConnection) 
      Return _auditConnection 
     End Get 
    End Property 
End Class 

Public Class DBConnectionsProxy 

    Private _ConnectionsFactory As IConnectionFactory 
    Private _CurrentConnectionsFactory As IConnectionFactory 

    Public Sub New(ByVal connectionFactory As IConnectionFactory) 
     'check that a connection factory is provided otherwise nothing will work 
     If connectionFactory Is Nothing Then 
      Throw New NullReferenceException("You must provide a connection factory") 
     Else 
      _ConnectionsFactory = connectionFactory 
      _CurrentConnectionsFactory = connectionFactory 
     End If 
    End Sub 

    Friend Property ConnectionFactory() As IConnectionFactory 
     Get 
      Return _CurrentConnectionsFactory 
     End Get 
     Set(ByVal value As IConnectionFactory) 
      _CurrentConnectionsFactory = value 
     End Set 
    End Property 

    Public ReadOnly Property GetMasterConnection() As Npgsql.NpgsqlConnection 
     Get 
      Return _CurrentConnectionsFactory.GetMasterConnection.Connection 
     End Get 
    End Property 

    Public ReadOnly Property GetArchiveConnection() As Npgsql.NpgsqlConnection 
     Get 
      Return _CurrentConnectionsFactory.GetArchiveConnection.Connection 
     End Get 
    End Property 

    Public ReadOnly Property GetWarehouseConnection() As Npgsql.NpgsqlConnection 
     Get 
      Return _CurrentConnectionsFactory.GetWarehouseConnection.Connection 
     End Get 
    End Property 

    Public ReadOnly Property GetAuditConnection() As Npgsql.NpgsqlConnection 
     Get 
      Return _CurrentConnectionsFactory.GetAuditConnection.Connection 
     End Get 
    End Property 


    ''' <summary> 
    ''' Reset current connection factory to original connection factory this proxy was instantiated with 
    ''' </summary> 
    ''' <remarks></remarks> 
    Public Sub ResetConnection() 
     _CurrentConnectionsFactory = _ConnectionsFactory 
    End Sub 

    ''' <summary> 
    ''' Changes the master connection returned for the current connection factory 
    ''' </summary> 
    ''' <param name="connectionDetail">Connection information for master database</param> 
    ''' <remarks></remarks> 
    Public Sub SetMasterConnection(ByVal connectionDetail As DBConnectionDetail) 
     Me.SetAllConnections(connectionDetail, _CurrentConnectionsFactory.GetArchiveConnection, _ 
          _CurrentConnectionsFactory.GetWarehouseConnection, _CurrentConnectionsFactory.GetAuditConnection) 
    End Sub 

    ''' <summary> 
    ''' Changes the archive connection returned for the current connection factory 
    ''' </summary> 
    ''' <param name="connectionDetail">Connection information for archive database</param> 
    ''' <remarks></remarks> 
    Public Sub SetArchiveConnection(ByVal connectionDetail As DBConnectionDetail) 
     Me.SetAllConnections(_CurrentConnectionsFactory.GetMasterConnection, connectionDetail, _ 
          _CurrentConnectionsFactory.GetWarehouseConnection, _CurrentConnectionsFactory.GetAuditConnection) 
    End Sub 

    ''' <summary> 
    ''' Changes the warehouse connection returned for the current connection factory 
    ''' </summary> 
    ''' <param name="connectionDetail">Connection information for warehouse database</param> 
    ''' <remarks></remarks> 
    Public Sub SetWarehouseConnection(ByVal connectionDetail As DBConnectionDetail) 
     Me.SetAllConnections(_CurrentConnectionsFactory.GetMasterConnection, _CurrentConnectionsFactory.GetArchiveConnection, _ 
          connectionDetail, _CurrentConnectionsFactory.GetAuditConnection) 
    End Sub 

    ''' <summary> 
    ''' Changes the audit connection returned for the current connection factory 
    ''' </summary> 
    ''' <param name="connectionDetail">Connection information for audit database</param> 
    ''' <remarks></remarks> 
    Public Sub SetAuditConnection(ByVal connectionDetail As DBConnectionDetail) 
     Me.SetAllConnections(_CurrentConnectionsFactory.GetMasterConnection, _CurrentConnectionsFactory.GetArchiveConnection, _ 
          _CurrentConnectionsFactory.GetWarehouseConnection, connectionDetail) 
    End Sub 


    ''' <summary> 
    ''' Sets the current connection factory to a custom connection factory using the supplied connection 
    ''' </summary> 
    ''' <param name="masterConnectionDetail">Connection information for master database</param> 
    ''' <param name="archiveConnectionDetail">Connection information for archive database</param> 
    ''' <param name="warehouseConnectionDetail">Connection information for warehouse database</param> 
    ''' <remarks></remarks> 
    Public Sub SetAllConnections(ByVal masterConnectionDetail As DBConnectionDetail, _ 
           ByVal archiveConnectionDetail As DBConnectionDetail, _ 
           ByVal warehouseConnectionDetail As DBConnectionDetail, _ 
           ByVal auditConnectionDetail As DBConnectionDetail) 

     Dim customConnFactory As New CustomConnectionFactory 
     customConnFactory.SetMasterConnectionDetail(masterConnectionDetail) 
     customConnFactory.SetArchiveConnectionDetail(archiveConnectionDetail) 
     customConnFactory.SetWarehouseConnectionDetail(warehouseConnectionDetail) 
     customConnFactory.SetAuditConnectionDetail(auditConnectionDetail) 

     _CurrentConnectionsFactory = customConnFactory 
    End Sub 


End Class 
관련 문제