2010-04-26 4 views
0

C#에서 친구가없는 이유에 대한 질문이 광범위하게 논의되었습니다.클래스 아키텍처, 친구 허용하지 않음

다음과 같은 디자인 문제가 있습니다.

나는 두 클래스가 있습니다 TradingSystem주문입니다. Trading System 클래스에는 하나의 공용 함수 AddOrder (Order ord) 만 있습니다. 클라이언트는이 기능 만 호출 할 수 있습니다. 다른 모든 논리는 숨겨져 있어야합니다. 클래스는 시장 이벤트를 청취하고 TradingSystem ExecuteOrder의 다른 함수를 호출해야하므로 public으로해야합니다. 그렇게 함으로서 거래 시스템의 고객이이 기능을 호출 할 수 있도록 허용하고 싶지 않습니다.

UPDATE 주문 클래스와 TradingSystem는 별도의 어셈블리에 살고있다. 주문 클래스는 클래스이며 다른 많은 클래스가 파생 될 수 있습니다. 모든 클라이언트가 어셈블리 외부에있는 가정

class TradingSystem 
    { 
    // Trading system stores list of orders 
     List<Order> _orders; 

    // this function is made public so that Order class can call it when need 
    // but other class must not call it 
     public ExecuteOrder(Order ord) 
    { 
// some logic 
    } 
     // this function is made public for external clients 
     public AddOrder(OrderRequest ordreq) 
    { 
     // omitted code 
     // create order and pass it this 
     order.OnOrderAdded(this); 
    } 
    } 

    class Order 
    { 
     // reference to TradingSystem class is stored to call it methods 
     TradingSystem _ts; 

     public void OnOrderAdded(TradingSystem ts) 
    { 
     _ts = ts; 
    } 

    // this function is called on timer 
    void OnMarketEvent() 
    { 
     if(/*some logic*/) 
     _ts.ExecuteOrder() 
    } 
    } 

답변

2

고객은 TradingSystem에 대해 하나, 주문에는 하나의 인터페이스를 만들 수 있습니다. 귀하의 고객은 귀하의 첫 번째 인터페이스를 얻게되며, 주문은 TradingSystem 자체 대신에 두 번째 인터페이스를 갖게됩니다.

public interface I1 
{ 
    void AddOrder(Order ord); 
} 

public interface I2 
{ 
    void ExecuteOrder(Order ord); 
} 

internal class TradingSystem: I1, I2 
{ 
    ... 
1

, 당신은 internal로 ExecuteOrder을 선언 할 수 있습니다.

그렇지 않으면 한 메서드를 노출하고 해당 인터페이스를 클라이언트 대신 개체에 제공 할 수있는 인터페이스를 선언 할 수 있습니다. 실제로 API가 본질적으로 단수이면 Action<OrderRequest> 이상을 클라이언트에 제공 할 수 있습니다.

2

AddOrderExecuteOrder을 내부 어셈블리로 변경하고 동일한 어셈블리에 두 개의 프록시 클래스가 있으며 각 어셈블리는 TradingSystem으로 만들고이 중 하나를 위임 할 수 있습니다.

그런 다음 AddOrder을 호출해야하는 모든 것을 제공 할 수있는 프록시와 그저 호출 할 수있는 프록시 인 ExecuteOrder을 호출해야합니다.

잠재적으로 두 가지 방법을 모두 공개하고 TradingSystem이 두 개의 인터페이스를 구현하도록 만들 수 있습니다. 그러나 클라이언트가 콘크리트 유형으로 캐스트하고 어쨌든 호출 할 수 있습니다.

액세스 수식어는 일반적으로 보안 계층으로 사용하면 안됩니다.이 방법이 실제 거래 시스템 인 경우 (원하는 분리 유형의 예가 아닌) 보안을 기대합니다. 오히려 다르게 구현되어야한다.

+0

@ 존 :'TradingSystem' 내부에서 클라이언트가 캐스팅하지 못하게하겠다고 선언하지 않겠습니까? – Vlad

+0

@Vlad : TradingSystem으로의 캐스팅을 막을 수는 있지만, 다른 인터페이스로 캐스팅하는 것을 막을 수는 없습니다 (두 개의 인터페이스가 있다고 가정). –

1

두 클래스가 모두 동일한 어셈블리에 있고 클라이언트가 internal 키워드를 사용할 수없는 경우.

internal 키워드는 유형 및 유형 구성원에 대한 액세스 수정 자입니다. 내부 형식 또는 멤버는 같은 어셈블리의 파일에서만 액세스 할 수있는 입니다. 그렇지 않은 경우

당신은 여전히 ​​internal 키워드를 사용할 수 있지만 TradingSystem를 선언 어셈블리의 내부가 Order이 들어있는 어셈블리에 볼 수 있도록 선언해야합니다. 이를 위해 InternalsVisisibleTo 속성을 사용할 수 있습니다.

InternalsVisibleToAttribute Class

당신은 클라이언트가 여전히 반사를 통해 이러한 방법, 심지어 개인 사람을 호출 할 수 있음을 유의하십시오.

+0

주문 및 TradingSystem은 다른 어셈블리에 속합니다 –

+0

@Captain Comic, 두 번째 옵션은 여전히 ​​실행 가능합니다. –

2

는 C# 키워드 internal는 VB의 Friend에 해당합니다. 이것을 InternalsVisisibleToAttribute과 결합하면이 예에서 집에 있어야합니다.

관련 문제