Facade Design Pattern (with Java Code)

'Head First Design Pattern' Code Included
Jun 03, 2024
Facade Design Pattern (with Java Code)

What is Facade Pattern?

Trait

: 패턴이 적용된 ‘Façade Class Class 계층의 서버’ 또는 ‘패키지’의 외부에서

접근이 가능하고 노출된 Facade Class가

Client 또는 외부의 actor가 요청하는 기능 수행에 필요한 패키지 내부 class들의 연산을

미리 구성(composition)으로 가지고 있다.

이 기능들은 내부 class를 직접적으로 외부에 노출시키지 않은 채

의존성만 주입되는 구조로 돼 있다.

외부의 기능 수행 요청이 있을 시 Façade Class는 각 내부 class들을 호출하여

요청된 기능을 수행한다.

해당 패턴은 마치 Façade(입구)로 그 내부 구조를 대략적으로 파악할 수 있는

건물 입구와 그 내부와 같다는 의미에서 Façade Pattern이라는 이름이 붙었으며,

이 건물의 입구(Façade)와 같은 ‘Façade Class의 구성(composition)은’

입구의 모습이 보여주는 내부의 구조가 추측될 수 있는 ‘입구의 모습’과 같다.

외부에서 입구만 보고 파악할 수 있다는 이름과 같이 내부의 Class는

패턴의 package 외부에서 직접 접근할 수 없다.

Head First Design Pattern Sample Code

class HomeTheaterTestDrive

  • request related class type의 객체를 생성하고 Facade Class에 넘겨

    Facade type의 객체를 생성하고,

    Facade Class type의 객체에게 watchMovie(), endMovie() 메시지를 전달합니다.

package facade.hometheater;

public class HomeTheaterTestDrive {
    /*
        해당 class는 Controller와 비슷한 역할의
        실행부 포함 class로,
        Amplifier(아날로그 신호 증폭 앰프), Tuner(AM/FM 튜너),
        StreamingPlayer(영상 재생기기), CDPlayer(Cd 플레이어(리더기)),
        Projecter(영상 프로젝터), TheaterLights(영화관 조명),
        Screen(영상 스크린), PopcornPopper(팝콘 튀김기계)
        타입의 객체(괄호 안의 실제 사물)를 생성합니다.
        이 객체는 home theater와 연관된 요청을 수행하기 위한 메시지를 분산하여 담당하며,
        HomeTheaterFacade Class의 constructor에
        각 객체는 type이 연결된 채로 arguments로서 넘겨집니다.
        다만 main()에서 CdPlayer 객체에 대한 메시지 전달 연산은 구현되지 않았습니다.

        main()은 실행 요청 시 해당 객체들의 생성과 동시에 Façade type의 객체를 생성하고
        이 객체에 watchMovie(homeTheater영화 상영 시작),
        endMovie(homeTheater 영화 상영 종료)를 수행합니다.
        해당 Class는 이름 그대로 TestDrive가 핵심이기 때문에,
        상영 이후 즉시 종료 메시지를 Façade Class type object에 전달합니다.
    */
    public static void main(String[] args) {
        // 	Input이 없기 때문에 간단하게 annotation 작성하였습니다.

        /*
            Creates hometheater place related objects
                    Amplifier, Tuner, StreamingPlayer, CDPlayer,
            Projecter, TheaterLights, Screen, PopcornPopper type assigned.
            The HomeTheaterTestDrive main() runs watchMovie() and endMovie()
            in a row.
        */

        Amplifier amp = new Amplifier("Amplifier");
        Tuner tuner = new Tuner("AM/FM Tuner", amp);
        StreamingPlayer player = new StreamingPlayer("Streaming Player", amp);
        CdPlayer cd = new CdPlayer("CD Player", amp);
        Projector projector = new Projector("Projector", player);
        TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
        Screen screen = new Screen("Theater Screen");
        PopcornPopper popper = new PopcornPopper("Popcorn Popper");

        HomeTheaterFacade homeTheater =
                new HomeTheaterFacade(amp, tuner, player,
                        projector, screen, lights, popper);

        homeTheater.watchMovie("Raiders of the Lost Ark");
        homeTheater.endMovie();
    }
}

class HomeTheaterFacade

package facade.hometheater;

public class HomeTheaterFacade {
    Amplifier amp;
    Tuner tuner;
    StreamingPlayer player;
    CdPlayer cd;
    Projector projector;
    TheaterLights lights;
    Screen screen;
    PopcornPopper popper;

    public HomeTheaterFacade(Amplifier amp,
                             Tuner tuner,
                             StreamingPlayer player,
                             Projector projector,
                             Screen screen,
                             TheaterLights lights,
                             PopcornPopper popper) {

    // CdPlayer를 제외한 Type의 Field reference 생성 및 arguments참조 후             생성자로 생성된 object에 this()를 통해 class member로 할당.

        this.amp = amp;
        this.tuner = tuner;
        this.player = player;
        this.projector = projector;
        this.screen = screen;
        this.lights = lights;
        this.popper = popper;
    }

    public void watchMovie(String movie) {
        System.out.println("Get ready to watch a movie...");
        popper.on();
        popper.pop();
        lights.dim(10);
        screen.down();
        projector.on();
        projector.wideScreenMode();
        amp.on();
        amp.setStreamingPlayer(player);
        amp.setSurroundSound();
        amp.setVolume(5);
        player.on();
        player.play(movie);
    }


    public void endMovie() {
        System.out.println("Shutting movie theater down...");
        popper.off();
        lights.on();
        screen.up();
        projector.off();
        amp.off();
        player.stop();
        player.off();
    }

    public void listenToRadio(double frequency) {
        System.out.println("Tuning in the airwaves...");
        tuner.on();
        tuner.setFrequency(frequency);
        amp.on();
        amp.setVolume(5);
        amp.setTuner(tuner);
    }

    public void endRadio() {
        System.out.println("Shutting down the tuner...");
        tuner.off();
        amp.off();
    }
}

class Amplifier

package facade.hometheater;

public class Amplifier {
	String description;
    // Tuner, StreaminPlayer class에 의존성을 갖습니다.
	Tuner tuner;
	StreamingPlayer player;
	
	public Amplifier(String description) {
		this.description = description;
	}
 
	public void on() {
		System.out.println(description + " on");
	}
 
	public void off() {
		System.out.println(description + " off");
	}
 
	public void setStereoSound() {
		System.out.println(description + " stereo mode on");
	}

    // Subwoofer는 스피커와 기기가 분리돼 있으므로, Speaker Class가 추가된다면 
    // Speaker의 구성으로 할 지도 결정해야 합니다.

 
	public void setSurroundSound() {
		System.out.println(description + " surround sound on (5 speakers, 1 subwoofer)");
	}
 
	public void setVolume(int level) {
		System.out.println(description + " setting volume to " + level);
	}

	public void setTuner(Tuner tuner) {
		System.out.println(description + " setting tuner to " + player);
		this.tuner = tuner;
	}
  
	public void setStreamingPlayer(StreamingPlayer player) {
		System.out.println(description + " setting Streaming player to " + player);
		this.player = player;
	}
 
	public String toString() {
		return description;
	}
}

class CdPlayer

package facade.hometheater;

public class CdPlayer {
	String description;
	int currentTrack;
	Amplifier amplifier;
	String title;
	
	public CdPlayer(String description, Amplifier amplifier) {
		this.description = description;
		this.amplifier = amplifier;
	}
 
	public void on() {
		System.out.println(description + " on");
	}
 
	public void off() {
		System.out.println(description + " off");
	}

	public void eject() {
		title = null;
		System.out.println(description + " eject");
	}
 
	public void play(String title) {
		this.title = title;
		currentTrack = 0;
		System.out.println(description + " playing \"" + title + "\"");
	}

	public void play(int track) {
		if (title == null) {
			System.out.println(description + " can't play track " + currentTrack + 
					", no cd inserted");
		} else {
			currentTrack = track;
			System.out.println(description + " playing track " + currentTrack);
		}
	}

	public void stop() {
		currentTrack = 0;
		System.out.println(description + " stopped");
	}
 
	public void pause() {
		System.out.println(description + " paused \"" + title + "\"");
	}
 
	public String toString() {
		return description;
	}
}

class PopcornPopper

package facade.hometheater;

public class PopcornPopper {
    String description;

    public PopcornPopper(String description) {
        this.description = description;
    }

    public void on() {
        System.out.println(description + " on");
    }

    public void off() {
        System.out.println(description + " off");
    }

    public void pop() {
        System.out.println(description + " popping popcorn!");
    }


    public String toString() {
        return description;
    }
}

class Projector

package facade.hometheater;

public class PopcornPopper {
    String description;

    public PopcornPopper(String description) {
        this.description = description;
    }

    public void on() {
        System.out.println(description + " on");
    }

    public void off() {
        System.out.println(description + " off");
    }

    public void pop() {
        System.out.println(description + " popping popcorn!");
    }


    public String toString() {
        return description;
    }
}

class Screen

package facade.hometheater;

public class Screen {
	String description;

	public Screen(String description) {
		this.description = description;
	}

	public void up() {
		System.out.println(description + " going up");
	}

	public void down() {
		System.out.println(description + " going down");
	}


	public String toString() {
		return description;
	}
}

class StreamingPlayer

package facade.hometheater;

public class StreamingPlayer {
	String description;
	int currentChapter;
	Amplifier amplifier;
	String movie;
	
	public StreamingPlayer(String description, Amplifier amplifier) {
		this.description = description;
		this.amplifier = amplifier;
	}
 
	public void on() {
		System.out.println(description + " on");
	}
 
	public void off() {
		System.out.println(description + " off");
	}
 
	public void play(String movie) {
		this.movie = movie;
		currentChapter = 0;
		System.out.println(description + " playing \"" + movie + "\"");
	}

	public void play(int chapter) {
		if (movie == null) {
			System.out.println(description + " can't play chapter " + chapter + " no movie selected");
		} else {
			currentChapter = chapter;
			System.out.println(description + " playing chapter " + currentChapter + " of \"" + movie + "\"");
		}
	}

	public void stop() {
		currentChapter = 0;
		System.out.println(description + " stopped \"" + movie + "\"");
	}
 
	public void pause() {
		System.out.println(description + " paused \"" + movie + "\"");
	}

	public void setTwoChannelAudio() {
		System.out.println(description + " set two channel audio");
	}
 
	public void setSurroundAudio() {
		System.out.println(description + " set surround audio");
	}
 
	public String toString() {
		return description;
	}
}

class TheaterLights

package facade.hometheater;

public class TheaterLights {
	String description;

	public TheaterLights(String description) {
		this.description = description;
	}

	public void on() {
		System.out.println(description + " on");
	}

	public void off() {
		System.out.println(description + " off");
	}

	public void dim(int level) {
		System.out.println(description + " dimming to " + level  + "%");
	}

	public String toString() {
		return description;
	}
}

class Tuner

package facade.hometheater;

public class Tuner {
	String description;
	Amplifier amplifier;
	double frequency;

	public Tuner(String description, Amplifier amplifier) {
		this.description = description;
	}

	public void on() {
		System.out.println(description + " on");
	}

	public void off() {
		System.out.println(description + " off");
	}

	public void setFrequency(double frequency) {
		System.out.println(description + " setting frequency to " + frequency);
		this.frequency = frequency;
	}

	public void setAm() {
		System.out.println(description + " setting AM mode");
	}

	public void setFm() {
		System.out.println(description + " setting FM mode");
	}

	public String toString() {
		return description;
	}
}
Share article

SW Engineering Blog