극좌 극우로 부터 시작해서, 높이가 낮은 사이드를 당기면서 최대값을 갱신하면 된다.

 

낮은 쪽을 당기는 이유는, 낮은 쪽 사이드가 정답일 경우가 없기 때문.(현재 최대값이 정답인 경우를 제외하고)

 

class Solution:
    def maxArea(self, height: List[int]) -> int:
        left = 0
        right = len(height) - 1
        ret = 0
        
        while(left < right):
            ret = max(ret, (right - left) * min(height[right], height[left]))
            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
                
        return ret

Components

 

. 모듈과 주입간의 다리 역할 = injector

. @Component 주석과 연관된 모듈들을 줄줄이 기록해둔다

@Singleton
@Component(modules = {
        NetworkModule.class,
        TwitterModule.class,
})
 
public interface TwitterComponent {
    Tweeter tweeter();
    Timeline timeline();
}
 
TwitterComponent component = Dagger_TwitterComponent.builder()
        .networkModule(new NetworkModule())
        .twitterModule(new TwitterModule("JakeWarton"))
        .build();
 
Tweeter tweeter = component.tweeter();
tweeter.tweet("asdasdasd");
 
Timeline timeline = component.timeline();
timeline.loadMore(20);
for(Tweet tweet : timeline.get()){
    System.out.println(tweet);
}
 

연관된 모듈들을 @Component 뒤에 기록해두었다. 

모듈이 제공하는 인스턴스들이 모두 싱글톤이었으므로, TwitterComponent도 싱글톤으로 지정했다.

 

인터페이스를 구성한 이 후, Dagger에서 제공하는 build()함수를 콜해서 컴포넌트들 만들 수 있다.

이 후 이 컴포넌트만 가지고 인스턴스를 가져올 수 있다.

 

사실 NetworkModule은 기본생성자를 가지고 있기 때문에 컴포넌트 생성코드에 네트워크 모듈은 부르지 않아도 되긴하다.

 

public class TwitterApplicatopn implements Runnable {
    private final Tweeter tweeter;
    private final Timeline timeline;
 
    @Inject
    public TwitterApplicatopn(Tweeter tweeter, Timeline timeline){
        this.tweeter = tweeter;
        this.timeline = timeline;
    }
 
    @Override
    public void run(){
        tweeter.tweet("asdasdasd");
 
        timeline.loadMore(20);
        for(Tweet tweet : timeline.get()){
            System.out.println(tweet);
        }
    }
}
 
@Singleton
@Component(modules = {
        NetworkModule.class,
        TwitterModule.class,
})
 
public interface TwitterComponent {
    TwitterApplicatopn app();
}
 
TwitterComponent component = Dagger_TwitterComponent.builder()
        .networkModule(new NetworkModule())
        .twitterModule(new TwitterModule("JakeWarton"))
        .build();
 

아니면 TwitterApplication 이라는 싱글 엔트리 포인트를 만들어 두었기 때문에, 이를 스레드화시키고 run()만 해서 작동시키는게 더 보편적인 개발패턴이란다.

 

 

 

 

 

 

 

Dagger는 자바와 안드로이드를 위한 빠른 의존성 주입을 제공한다.

 

의존성 주입이란, 구성요소간의 의존 관계가 코드 내부가 아닌 외부의 설정파일등을 통해 정의되게 하는 디자인 패턴이다. 이를 통해 모듈간의 결합도가 낮아지게 되므로, 단위 테스트가 쉬워지며 모듈의 재사용성이 높아진다.

 

public class TwitterApi {
    public void postTweet(String user, String tweet){
        OkHttpClient client = new OkHttpClient();
        Request request = client.newCall(request).execute();
    }
}
 
public class Tweeter {
    public void tweet(String tweet){
        TwitterApi api = new TwitterApi();
        api.postTweet("JakeWharton", tweet);
    }
}
 
 

Tweeter 클래스는 tweet 메소드를 제공하는데, 내부적으로 api 인스턴스를 생성하고, 이를 통해 메소드를 호출해 트윗을 포스트 한다.

또한 이 api는 내부적으로 HttpClient 인스턴스를 생성하고 리퀘스트를 만들어 실행한다.

 

이 코드는 매우 구리다. 왜냐하면 매번 request를 위해선 HttpClient 객체가 생성되므로 매우 낭비적이다.

 

코드를 다음과 같이 바꿔본다.

public class TwitterApi {
    private final OkHttpClient client = new OkHttpClient();
    
    public void postTweet(String user, String tweet){
        Request request = client.newCall(request).execute();
    }
}
 

이제 매 request 마다 OkClient 객체가 생성되지 않는다.

이것을 DI스러운 디자인 패턴으로 바꾸면 다음과 같다.

public class TwitterApi {
    private final OkHttpClient client;
 
    public TwitterApi(OkHttpClient client){
        this.client = client;
    }
 
    public void postTweet(String user, String tweet){
        Request request = client.newCall(request).execute();
    }
}
 

생성자는 외부에서 OkHttpClient 레퍼런스를 받아와서 대입시킬 뿐이다.

생성자가 바뀌었으니까 Tweeter 클래스도 바꿔야 한다. 다음과 같다.

public class Tweeter {
    public void tweet(String tweet){
        TwitterApi api = new TwitterApi(new OkHttpClient());
        api.postTweet("JakeWharton", tweet);
    }
}
 

하지만 여전히 낭비적인 요소가 있는데, 사용자가 tweet 할 때 마다 이 큰 객체를 만들어낸다.

똑같이 DI 스러운 디자인 패텅을 적용해보자.

public class Tweeter {
    private final TwitterApi api =new TwitterApi(new OkHttpClient());
    private final String user;
 
    public Tweeter(String user){
        this.user = user;
    }
 
    public void tweet(String tweet){
        api.postTweet("JakeWharton", tweet);
    }
}
 

생성자는 유저이름을 받아와 대입시킨다.

 

이제 다음과 같이 tweet 할 수 있다.

. Tweeter tweeter = new Tweeter("JakeWharton");

. tweeter.tweet("123123123")

. tweeter.tweet("456456456")

 

헌데 이제 타임라인이라는 추가기능을 넣는다고 가정해보자.

public class Timeline {
    private final List<Tweet> cache = new ArrayList<>();
    private final TwitterApi api = new TwitterApi(new OkHttpClient());
    private final String user;
    
    public Timeline(String user) {
        this.user = user;
    }
    
    public List<Tweet> get() { /*....*/ }
    public void loadMore(int amount) { /*....*/ }
}
 

위 클래스를 통해

. Timeline timeline = new TimeLine("JakeWharton");

. timeline.loadMore(20);

. for(Tweet tweet : timeline.get()) { System.out.println(tweet); }

 

타임라인 객체를 생성하고 트윗을 20개 불러와 get()메소드를 통해 출력하는 코드를 생각해보자.

문제는 타임라인 역시 api를 사용하므로 api 객체를 또 만드는 낭비가 발생할 수 있다는 것이다.

public class Timeline {
    private final List<Tweet> cache = new ArrayList<>();
    private final TwitterApi api;
    private final String user;
 
    public Timeline(TwitterApi api, String user) {
        this.api = api;
        this.user = user;
    }
 
    public List<Tweet> get() { /*....*/ }
    public void loadMore(int amount) { /*....*/ }
}
 

따라서 위에서 Tweeter 객체가 생성되면서 만들어진 api를 재사용할 수 있다.

----------------------------------------------------------------------------------------------------

Dagger v2는 다음과 같은 api를 제공한다.

. @Module + @Provides : 의존성 제공을 위한 메커니즘

. @Inject : 의존성 요청을 위한 메커니즘

. @Component : 모듈과 주입 사이의 다리역할

 

1. 의존성 제공

모듈이란 의존성을 제공하는 메소드들을 가진 클래스를 말한다. @Module을 클래스에, @Provides를 각 메소드에 붙여서 지정하면 된다. Tweeter 예제에 적용시키면 다음과 같다.

@Module
public class NetworkModule {
    @Provides @Singleton
    OkHttpCliet provideOkHttpClient() {
        return new OkHttpClient();
    }
    @Provides @Singleton
    TwitterApi provideTwitterApi(OkHttpClient client){
        return new TwitterApi(client);
    }
}
 
@Module
public class TwitterModule {
    private final String user;
 
    public TwitterModule(String user){
        this.user = user;
    }
 
    @Provides @Singleton
    Tweeter provideTweeter(TwitterApi api){
        return new Tweeter(api, user);
    }
 
    @Provides @Singleton
    Timeline provideTimeline(TwitterApi api){
        return new Timeline(api, user);
    }
}
 

모듈이 두 개 생겨났는데, 네트워크모듈은 api를 제공하고, 트위터모듈은 사용자와 타임라인을 제공한다.

정리해서 의존성 관계를 그래프로 나타내면 다음과 같다.

 

사용자나 타임라인이나 api가 있어야 제공받을 수 있다. 동시에 api는 OkHttpClient가 있어야 제공받을 수 있다.

만약 Tweeter객체를 만든다면 OkHttpClient객체까지 생성되지만, 이 후 Timeline객체를 만든다면 api는 이미 생성되어있으므로 OkHttpClient까지 새로이 만들어지진 않는다.

 

2. 의존성 요청

@Inject 로 표시하면 된다. 이 표시는 생성자, 필드, 메소드에 붙일 수 있다.

 

1) 생성자 주입

public class TwitterApplicatopn {
    private final Tweeter tweeter;
    private final Timeline timeline;
 
    @Inject
    public TwitterApplicatopn(Tweeter tweeter, Timeline timeline){
        this.tweeter = tweeter;
        this.timeline = timeline;
    }
}
 

위처럼 의존성이 private final 필드에 저장될 수 있다.

@Inject 표기로 dagger가 알아서 객체생성을 어떻게 해야 하는지 알게 되고 downstream injection을 가능케 한다. 무슨 말이냐면 만약 TwitterApplication 클래스를 inject하고 싶은 클래스가 있다면, 가능하다는 말이다.

더 자세히 설명하면 TwitterApi 생성자는 OkHttpClient 객체를 요구하는데, 이 객체는 TwitterModule에서 @Povides로 제공되고 있는 상황이다.

여기서 TwitterApi 생성자에 @Inject를 붙여주면, dagger가 알아서 객체를 끌어오므로, 모듈에 무수한 @provides 들을 손수 작성하지 않아도 된다.

문제는 네트워크모듈에서 provideTwitterApi는 싱글톤이었는데 @inject를 생성자에 붙이기만 하면 dagger는 매 번 api 요청이 들어올 때 마다 생성자를 호출할 것이다. 따라서 @Singleton을 붙여줘야 한다.

(뭔 말인지 모르겠다.)

결과는 다음과 같다.

@Singleton
public class TwitterApi {
    private final OkHttpClient client;
 
    @Inject
    public TwitterApi(OkHttpClient client){
        this.client = client;
    }
 
    public void postTweet(String user, String tweet){
        Request request = client.newCall(request).execute();
    }
}
 

2) 메소드 주입

 

@Inject를 메소드들에 붙있 수 있다. 이 메소드들의 매개변수들은 의존성들이다. 주입은 매개변수들이 완전히 인스턴스화 된 이후에 이루어진다. 이러한 사용예시 중에 가장 좋은 케이스는 this 객체를 의존성에 전달하는 것이다.

public class TwitterApplicatopn {
    private final Tweeter tweeter;
    private final Timeline timeline;
 
    @Inject
    public TwitterApplicatopn(Tweeter tweeter, Timeline timeline){
        this.tweeter = tweeter;
        this.timeline = timeline;
    }
 
    @Inject
    public void enableStreaming(Streaming streaming){
        streaming.register(this);
    }
}
 

 

3) 필드 주입

 

필드에 @Inject를 붙일 수 있다. 필드는 private 이나 final이면 안된다. 

 

 

 

-------------------------------------------------------------------------------------------------------------

 

Component

 

component가 모듈과 주입 사이의 다리(Injector)역할을 한다고 했다.

 

~20:00

 

+ Recent posts