import java.awt.Frame; // public class Test164 { public static void main( String[] args ) { Frame f = new Frame(); f.setSize( 600, 360 ); f.setVisible( true ); } }
class XFrame extends Frame { public XFrame() { setSize( 600, 360 ); setVisible( true ); } } // public class Test165 { public static void main( String[] args ) { new XFrame(); } }
상속과 생성자 함수로 같은 동작 구현
class XCanvas extends Canvas { public XCanvas() { setSize( 500, 200 ); setBackground( Color.YELLOW ); } // public void paint( Graphics g ) { Graphics2D g2 = (Graphics2D)g; // g2.setColor( Color.BLACK ); g2.drawRect( 10, 10, 50, 50 ); // 나중에 그린게 이전에 그린거 덮어버린다 ... g2.setColor( Color.GREEN ); g2.fillRect( 40, 40, 100, 100 ); } } // class XFrame extends Frame { public XFrame() { Panel p1 = new Panel(); p1.add( new XCanvas() ); // Panel p2 = new Panel(); p2.add( new TextField( 24 ) ); p2.add( new Button("Click") ); // add( p1 , BorderLayout.CENTER ); add( p2 , BorderLayout.SOUTH ); // setSize( 600, 360 ); setVisible( true ); } } // public class Test166 { public static void main( String[] args ) { new XFrame(); } }
Canvas
: 선을 긋고 그림을 그리고 이미지를 보여주는 등의 역할을 수행하는 클래스.
// 유연한 교체를 위한 코드 interface IFuelObs { public void onFuelChange( int fuel ); } // class Car { // 유연한 교체를 위한 코드 시작 private IFuelObs obs = null; public void setFuelObs( IFuelObs o ) { obs = o; } // 유연한 교체를 위한 코드 끝 private int fuel = 3; public void drive() { fuel--; // 유연한 교체를 위한 코드 if( obs != null ) { obs.onFuelChange( fuel ); } // 유연한 교체를 위한 코드 System.out.println("연료 1L 소모"); } } // 연료의 변화가 생기면 잔량을 찍어주는 클래스 class FuelGauge implements IFuelObs { public void onFuelChange( int fuel ) { System.out.println(">>" + fuel ); } } // public class Test168 { public static void main( String[] args ) { Car car = new Car(); // car.setFuelObs( new FuelGauge() ); car.setFuelObs( new FuelBomb() ); // car.drive(); car.drive(); // car.setFuelObs( null ); car.drive(); } } // class FuelBomb implements IFuelObs { public void onFuelChange( int fuel ) { if( fuel == 1 ) { System.out.println("폭탄터짐"); System.exit(0); } } }
연료의 상황을 체크하는 코드를 넣되 유연하게 교체가능하도록 만들 수 없을까?
연료계 역할의 클래스를 등록하면 Car 와 연동되다가 필요 없을 경우 빼거나 교체 할 수 있다. ( FuelGauge, FuelBomb )
Car 와 FuelGauge 는 별도의 클래스로 만들었다.
둘 다 IFuelObs 를 이용하는데
Car의 상태가 변경되는 것을 Gauge 에 통보하고 있다.
이러한 설계 기법을 관찰자 패턴 ( Observer Pattern )
이라고 한다.
FuelGauge -> FuelBomb 관찰자를 교체해도 잘 동작한다!
class XCanvas extends Canvas { public XCanvas() { setSize( 500, 200 ); setBackground( Color.YELLOW ); } } // class XFrame extends Frame { public XFrame() { Panel p1 = new Panel(); p1.add( new XCanvas() ); // Button btn = new Button("Click"); btn.addActionListener( new Apple() ); // Panel p2 = new Panel(); p2.add( new TextField( 24 ) ); p2.add( btn ); // add( p1 , BorderLayout.CENTER ); add( p2 , BorderLayout.SOUTH ); // setSize( 600, 360 ); setVisible( true ); } } // class Apple implements ActionListener { public void actionPerformed(ActionEvent e) { System.out.println("Apple::actionPerformed"); } } // public class Test169 { public static void main( String[] args ) { new XFrame(); } }
Button : 관찰 대상
Apple : 관찰자( implements ActionListener )
이 둘 사이는 ActionListener 라는 인터페이스로 느슨하게 연결되어 있고 Button 의 Action 상황이 벌어지면 addActionListener 로 등록된 관찰자가 오버라이딩하는 actionPerformed 가 호출되게 되는 설계이다.