※ 개인적인 메모 같은 느낌으로 설명이 적습니다.
Velocity 플러그인 개발 시작 문서를 읽어보고 있는데 눈에 띄는 코드가 있었다.
@Inject
이를 검색해보니 Google Guice 를 이용하여 Dependency Injection 를 효율적으로 사용할 수 있게끔하는 프레임워크인 듯하다.
Dependency injection 을 간단하게 요약하면 factory 패턴과 매우 흡사해 보인다.
구성요소로 크게 3가지가 있다.
- Services and clients (모듈 같은 개념)
- Interface
- Injectors
자세한 내용은 https://en.wikipedia.org/wiki/Dependency_injection 을 읽어보면 될 듯하고... C# 코드는 아래와 같다.
(코드 또한 위 링크에 있다.)
using System;
namespace DependencyInjection;
// Our client will only know about this interface, not which specific gamepad it is using.
interface IGamepadFunctionality {
string GetGamepadName();
void SetVibrationPower(float InPower);
}
// The following services provide concrete implementations of the above interface.
class XBoxGamepad : IGamepadFunctionality {
float VibrationPower = 1.0f;
public string GetGamepadName() => "Xbox controller";
public void SetVibrationPower(float InPower) => VibrationPower = Math.Clamp(InPower, 0.0f, 1.0f);
}
class PlaystationJoystick : IGamepadFunctionality {
float VibratingPower = 100.0f;
public string GetGamepadName() => "PlayStation controller";
public void SetVibrationPower(float InPower) => VibratingPower = Math.Clamp(InPower * 100.0f, 0.0f, 100.0f);
}
class SteamController : IGamepadFunctionality {
double Vibrating = 1.0;
public string GetGamepadName() => "Steam controller";
public void SetVibrationPower(float InPower) => Vibrating = Convert.ToDouble(Math.Clamp(InPower, 0.0f, 1.0f));
}
// This class is the client which receives a service.
class Gamepad {
IGamepadFunctionality _GamepadFunctionality;
// The service is injected through the constructor and stored in the above field.
public Gamepad(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;
public void Showcase() {
// The injected service is used.
var gamepadName = _GamepadFunctionality.GetGamepadName();
var message = $"We're using the {gamepadName} right now, do you want to change the vibrating power?";
Console.WriteLine(message);
}
}
class Program {
static void Main() {
var steamController = new SteamController();
// We could have also passed in an XboxController, PlaystationJoystick, etc.
// The gamepad doesn't know what it's using and doesn't need to.
var gamepad = new Gamepad(steamController);
gamepad.Showcase();
}
}
대충 이런 느낌이다.
(팩토리 패턴이랑 똑같긴한데 차이가 있다면 클래스들을 모듈화시켰다는 점에 있다.)
이 개념으로 https://github.com/google/guice/wiki/Motivation 을 읽어보면 될 듯하다.
아래 셈플 코드는 위 깃허브 링크에 있는거를 가져왔다. (나중에 내가 참고하기 위해...)
public interface BillingService {
Receipt chargeOrder(PizzaOrder order, CreditCard creditCard);
}
/*───────────────────────────────────────────────────────────────────────*/
public class RealBillingService implements BillingService {
private final CreditCardProcessor processor;
private final TransactionLog transactionLog;
@Inject
public RealBillingService(CreditCardProcessor processor,
TransactionLog transactionLog) {
this.processor = processor;
this.transactionLog = transactionLog;
}
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
try {
ChargeResult result = processor.charge(creditCard, order.getAmount());
transactionLog.logChargeResult(result);
return result.wasSuccessful()
? Receipt.forSuccessfulCharge(order.getAmount())
: Receipt.forDeclinedCharge(result.getDeclineMessage());
} catch (UnreachableException e) {
transactionLog.logConnectException(e);
return Receipt.forSystemFailure(e.getMessage());
}
}
}
/*───────────────────────────────────────────────────────────────────────*/
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
bind(BillingService.class).to(RealBillingService.class);
}
}
/*───────────────────────────────────────────────────────────────────────*/
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService billingService = injector.getInstance(BillingService.class);
...
}
그런데 결국 C#에서 적용하려면 mvvm 바인딩처럼 인스턴스를 생성해주고 각 모듈을 바인딩해줄 프레임워크가 필요해보인다. (있나? 찾아보니 있다 https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection )
댓글