반부패층 모드

유류 시스템과 통합하는 것은 아무런 즐거움도 없는 이정표이다. 이것은 이미 비밀이 아니다.엉망진창인 문서, 지원 부족, 혼란스러운 인터페이스, 소수의 휴면 버그는 통합 과정에서 직면할 수 있는 문제의 하위 집합일 뿐입니다.그러나 기술과/또는 정치적 이유로 일체화는 절대적으로 필요하다.유류 시스템과의 통합은 디자인 중인 시스템에 위험을 가져왔다. 유류 모델은 일반적으로 디자인이 좋지 않기 때문에 당신의 새로운, 디자인이 좋은 모델은 유류 통합에 손상될 수 있다.

통합 정책:


유류 시스템을 사용해야 하는 개발자는 네 가지 선택에 직면한다.
1. 전통을 버리다: 통용적인 용례를 가지고 항상 통합되는 이유는 아니다.개발자는 유류 시스템의 가치를 꼼꼼히 점검하고 통합 원가와 따져 이 옵션을 고려해야 한다.
2. 전통 준수: 조직이 전통 시스템을 교체할 계획이 없고 전통 모델의 질이 충분히 받아들일 수 있을 때 전통 모델을 지키면 모든 통합 원가를 없앨 수 있다.외곽 확장을 성숙하고 주도적인 위치를 차지하는 유류 시스템에 추가하는 경우 준수 방법을 진지하게 고려해야 한다.이 선택은 바퀴 재발명에 거부할 수 없이 빠져 시간과 돈을 낭비하고 상업적 가치가 거의 없는 해결 방안을 개발하기 때문에 과소평가되었다.
3 반부패층: 고도의 방어 전략으로 모델과 남겨진 모델의 부패를 분리하는 데 사용된다.
4 - 전통을 대체: 가장 불리한 선택.개발자가 동시에 새로운 모델을 개발할 때 남겨진 시스템의 대형 복잡한 모델(특히 이 모델들이 시스템의 핵심 분야에 속할 때)을 점차적으로 도태시키는 것을 피해야 한다. 왜냐하면 이런 웅대한 시도는 기대하지 않는 결과를 낳기 쉽기 때문이다.
반부패층 해결 방안을 시도하기 전에 옵션 1과 2를 꼼꼼히 반성해야 합니다.반부패층은 매우 추하고 복잡해질 수 있으며, 그 밖에 유지보수와 지원이 필요한 새로운 요소를 구성하여 조직의 배경도에 추가할 것이다.반부패층 모델을 논의하기 전에 두 가지 두드러진 디자인 모델을 간단히 이야기합시다.

정면:


Façade는 복잡한 시스템에 더욱 간단한 인터페이스를 제공하는 모델이다.외관은 인터페이스 시스템의 모델을 따르고 자신의 새로운 모델을 도입하는 것을 피해야 한다. 즉, 그들은 같은 언어를 사용해야 한다.
다음 인터페이스가 있는 스케줄 계획 시스템을 구상합니다.
public interface ITripService
{
    void BookAirline();
    void ReserveHotelRoom();
    void ReserveTouristAttractionTickets();
}
필요한 경우 다음 입면을 통해 더욱 간단한 인터페이스를 제공하여 전체 작업의 실행을 조율할 수 있습니다.
public interface ITripServiceFacade
{
    void PlanItinerary();
}

어댑터:



벽 어댑터
어댑터는 클라이언트가 이해할 수 있는 인터페이스를 제공함으로써 두 개의 호환되지 않는 추상적인 통신을 허용하는 모델이다.어댑터는 클라이언트의 언어를 사용하여 다른 서브시스템에 적응할 수 있다.
다음과 같은 인터페이스가 있는 차량 호출 어플리케이션을 생각해 보십시오.
public interface ITransportationService
{
    void StartTrip(string country, Zipcode from, Zipcode to);
}
그러나 일부 국가에서 여행은 Zipcode가 아닌 출처지와 목적지의 정확한 좌표에 따라 비용을 지불해야 한다는 것을 발견하면 어댑터를 제공한다.
public interface ITransportationServiceAdapter
{
    void StartTrip(Coordinates from, Coordinates to);
}
어댑터는 클라이언트의 언어를 사용하고 어댑터에 해당하는 요청을 하는 것을 책임집니다.

반부패층:



로마성을 삼킨 큰 불
반부패 패층은 하나의 외관, 어댑터와 변환기를 결합시켜 모델을 통합해야 하는 다른 모델의 부패와 분리시켰다.만약 두 모델 사이에 고객-공급업체 관계가 존재한다면 반부패층은 단방향일 수도 있고 그렇지 않으면 양방향일 수도 있다.
이 모델을 설명하기 위해 우리는 먼저 전자상거래 응용 프로그램을 고려한다. 이 응용 프로그램은 주문 발송에 필요한 소포의 수량과 사이즈를 추정하여 주문서의 발송 원가를 표시한 다음에 복잡한 네트워크 역행 알고리즘을 사용하여 가장 저렴한 발송 노선을 찾는다.그 중에서 우리는 두 가지 서로 다른 배경을 신속하게 추정할 수 있다. 그것이 바로 운송과 포장이다. 각각 다른 기능과 완전히 독립된 모델을 가지고 있다.
사실은 이 조직이 이미 여러 해 동안 사용한 전통적인 포장 서비스를 가지고 있다는 것을 증명한다. 왜냐하면 이 조직은 전략을 전자상거래로 전환하기 전에 포장 업계에 전문적으로 종사했기 때문이다.구조자가 유류 포장 서비스를 자세히 검사할 때 그들은 유류와의 통합이 불가피하다는 것을 깨달았다. 이 서비스는 매우 복잡하기 때문에 (대량의 지식이 유류에 압축되었다는 것을 나타낸다) 유류를 포기하거나 대규모 교체를 시도하는 것은 서투른 해결 방안이다.더욱 자세한 검사도 기존의 규칙을 고수하는 방법을 배제했다. 전통 모델은 이미 유행이 지났고 현재의 상업 모델에 적합하지 않기 때문에 운송 환경을 전통 포장 모델과 일치시키면 운송 분야의 높은 부패율을 초래할 수 있다.
불행하게도 패키지 서비스는 너무 낡고 문서 기록이 없고 많은 오류로 악명이 높다. 이런 오류로 인해 시스템의 다른 구성 요소들이 임시 해결 방법을 취하게 되었다. 그 밖에 이 서비스를 작성한 원시 개발자는 조직을 떠났고 발송팀은 완전히 독립되었다.이 점에서 구조자는 운송 상하문과 포장 상하문을 통합시키고 반부패층을 이용하여 운송 모델과 유류 모델을 분리해야 한다고 결정했다.
전통적인 포장 모형을 더욱 자세히 살펴보고 모형의 약점을 돋보이게 하며 운송 모형을 어떻게 파괴하는지 살펴보자.
namespace Warehouse.Packaging 
{
    public class Container 
    { 
        //Irrelevant details
    }

    public class Package 
    { 
        public double LengthInInches { get; }
        public double WidthInInches { get; }
        public double HeightInInches { get; }
    }

    public class Item 
    {
        public double LengthInInches { get; }
        public double WidthInInches { get; }
        public double HeightInInches { get; }
    }

    public class Warehouse 
    {
        public string Code { get; }
        public string ZipCode { get; }
        public IEnumerable<Container> AvailableContainers { get; }
        //Further details of a messy model
    }

    public interface ILegacyPackagingService 
    {
        bool ValidateItemDimensions (IEnumerable<Item> items);
        IEnumerable<Package> PackageItems (IEnumerable<Item> items, Warehouse warehouse);
        IEnumerable<Package> OptimizePackaging (IEnumerable<Package> packages);
    }
}
위 영역 모델에는 다음과 같은 몇 가지 문제가 있습니다.
1-ILegacyPackagingService은 복잡한 인터페이스를 제공합니다. 그 중에서 검증, 포장과 최적화는 세 가지 독립된 API로 제공됩니다. 이것은 좋은 이유일 수 있습니다. 그러나 이것은 운송 모델의 수요에 부합되지 않습니다. 운송의 측면에서 볼 때 모든 조작이 하나의 단일한 조작으로 간주되기 때문입니다.
2-ItemPackage 모델은 영국제를 사용하는데 이것은 모든 새로운 모델에서 공제를 사용하는 새로운 조직 범위 정책과 충돌한다.
3 - 포장 모듈의 창고 모델은 이미 유행이 지났고 자신의 창고의 업무 모델을 반영하지 않는다.
4-PackageItems에 정의된 ILegacyPackagingService API는 패키지 논리와 Warehouse 모델 간의 결합을 도입했다. 패키지 이전에는 조직의 지정된 창고 중 하나에서만 할 수 있는 조작으로 간주되기 때문이다.그러나 현재의 운송 모델은 외부 공급업체의 저장 시설에서 제품을 직접 운송할 수 있기 때문에 이런 가설을 지원할 수 없다.
분명히 반부패층은 아직 해야 할 일이 많다.상술한 모든 문제가 운송 모델에 누설되는 것을 허용하면 파손된 모델이 발생하는데 이 모델은 시스템의 모든 약점을 가지고 있다.첫 번째 문제를 완화하기 위해 우리는 반부패층에 하나의 외관을 도입했다.
namespace Warehouse.Packaging.AntiCorruption.Shipping 
{
    public interface IPackagingServiceFacade 
    {
        IEnumerable<Warehouse.Packaging.Package> PackageItems (IEnumerable<Item> items, Warehouse warehouse);
    }

    public class PackagingServiceFacade : IPackagingServiceFacade 
    {
        private readonly ILegacyPackagingService _packagingService;

        public PackagingServiceFacade (ILegacyPackagingService packagingService) 
        {
            _packagingService = packagingService;
        }

        public IEnumerable<Warehouse.Packaging.Package> PackageItems (IEnumerable<Item> items, Warehouse warehouse) 
        {
            if (_packagingService.ValidateItemDimensions (items)) 
            {
                var packages = _packagingService.PackageItems (items, warehouse);
                var optimizedPackages = _packagingService.OptimizePackaging (packages);
                return optimizedPackages;
            }

            return Enumerable.Empty<Package> ();
        }
    }
}
Façade는 패키지 서비스와 같은 모델을 사용하고 모델 요소를 추가하지 않았으며 언어를 유지했습니다.외관은 모델에게만 더욱 우호적인 인터페이스를 제공했다.외관은 Warehouse.Packaging 모듈/명칭 공간에 놓여 있으며, 이 명칭 공간은 패키지 상하문(반부패층은 여러 모듈을 뛰어넘을 수 있음)을 포함한다.
두 번째 문제를 해결하기 위해 반부패 계층은 두 컨텍스트에서 사용되는 서로 다른 모델 간에 매핑할 수 있도록 변환기 객체를 정의합니다. 다음 예제에서는 AutoMapper를 사용하여 매핑 작업을 간단하게 설명합니다.
namespace Logistics.Shipping.AntiCorruption.Packaging
{
    public class PackagerProfile : Profile
    {
        private const double InchesCmConversionConst = 0.39370;

        public PackagerProfile()
        {
            CreateMap<Product, Item>()
                .ForMember(dst => dst.LengthInInches, opt => opt.MapFrom(src => src.LengthInCm * InchesCmConversionConst))
                .ForMember(dst => dst.WidthInInches, opt => opt.MapFrom(src => src.WidthInCm * InchesCmConversionConst))
                .ForMember(dst => dst.HeightInInches, opt => opt.MapFrom(src => src.HeightInCm * InchesCmConversionConst));

            CreateMap<Warehouse.Packaging.Package, Logistics.Shipping.Package>()
                .ForMember(dst => dst.LengthInCm, opt => opt.MapFrom(src => src.LengthInInches / InchesCmConversionConst))
                .ForMember(dst => dst.WidthInCm, opt => opt.MapFrom(src => src.WidthInInches / InchesCmConversionConst))
                .ForMember(dst => dst.HeightInCm, opt => opt.MapFrom(src => src.HeightInInches / InchesCmConversionConst));
        }
    }
}
변환기는 호환되지 않는 모델을 왔다갔다할 수 있다.
세 번째와 네 번째 문제를 처리하기 위해 우리는 반부패층에 어댑터를 도입했다. 이 어댑터는 운송 서비스에 더욱 호환되는 인터페이스를 제공했다. 이 인터페이스는 Warehouse모델과 느슨하게 결합하는 것이 아니라 Container값 대상을 사용하여 포장 기능을 표시한다.
namespace Logistics.Shipping.AntiCorruption.Packaging
{
    public interface IPackagingService 
    {
        IEnumerable<Logistics.Shipping.Package> PackageItems (IEnumerable<Product> items, IEnumerable<Container> containers);
    }

    public class PackagingServiceAdapter : IPackagingService 
    {
        private readonly IPackagingServiceFacade _packagingServiceFacade;
        private readonly IMapper _mapper;

        public PackagingServiceAdapter (IPackagingServiceFacade packagingServiceFacade, IMapper mapper) 
        {
            _packagingServiceFacade = packagingServiceFacade;
            _mapper = mapper;
        }

        public IEnumerable<Logistics.Shipping.Package> PackageItems (IEnumerable<Product> products, IEnumerable<Container> containers) 
        {
            Warehouse warehouse; //Logic to initialize a transient dummy warehouse
            var items = _mapper.Map<IEnumerable<Item>> (products); //Using the translator to map the Product model to an Item
            var packages = _packagingServiceFacade.PackageItems (items, warehouse); //Calling the Façade 
            return _mapper.Map<IEnumerable<Logistics.Shipping.Package>> (packages); //Mapping the Packager's result to the Package model defined in the Shipping context
        }
    }
}
그 결과는 전통적인 포장 서비스와 통합되어 전통적인 손상을 입지 않는 운송 모델이다.
namespace Logistics.Shipping 
{
    public class Zone 
    { 
    }

    public class Product 
    {
        public double LengthInCm { get; }
        public double WidthInCm { get; }
        public double HeightInCm { get; }
    }

    public class Package 
    {
        public double LengthInCm { get; }
        public double WidthInCm { get; }
        public double HeightInCm { get; }
    }

    public class Courier 
    {
        private IPackagingService _packagingService;

        public double GetQuote (IEnumerable<Product> items, Zone source, Zone destination) 
        {
            var packagingCapabilities = _capabilitiesService.GetPackagingCapabilities (source);
            var packages = _packagingService.PackageItems (items, packagingCapabilities.Containers);
            //Shipping specific logic goes here
        }
    }
}
영역 모형의 대략적인 지도는 다음과 같다.

간단하게 보기 위해서 반부패층에 대한 상세한 정보를 생략하였다.

결론



중국의 만리장성
반부패층을 개발하는 것은 시간이 소모되는 과정으로 대량의 분석과 개발 작업이 필요하다.구조자는 즉시 이 해결 방안으로 넘어가서는 안 되고, 다른 간단한 대체 방안을 고려해야 한다. 그러나 다른 선택이 없을 때, 반부패층은 보루 주위의 벽처럼 적대적인 침입을 방지하고, 당신의 모델이 외부의 영향을 받지 않도록 보호하며, 당신이 독립적으로 일할 수 있도록 허락한다.

좋은 웹페이지 즐겨찾기