기본 아이디어
- Adapter 패턴은 클래스의 인터페이스를 클라이언트가 기대하는 다른 인터페이스로 변화(어댑팅)한다. 이는 호환성 없는 인터페이스 때문에 함께 사용할 수 없는 클래스를 개조하여 함께 작동하도록 해준다.
// ResultSet interface를 구현한 ResultSetAdapter
public class ResultSetAdapter implements java.sql.ResultSet
{
public ResultSetAdapter() {}
public boolean next() throws SQLException {throw new SQLException("ResultSet.next() unsupported");}
public int findColumn(String columnName)throws SQLException
{throw new SQLException("ResultSet.findColumn(String columnName) unsupported");}
public void updateObject(String colIndex, Object obj) throws SQLException {throw new SQLException("ResultSet.updateObject(String colIndex, Object obj) unsupported");}
public void updateObject(String colIndex, Object obj, int s) throws SQLException {throw new SQLException("ResultSet.updateObject(String colIndex, Object obj, int s) unsupported");}
public Statement getStatement() throws SQLException {throw new SQLException("ResultSet.getStatement() unsupported");}
public void close() throws SQLException {throw new SQLException("ResultSet.close() unsupported");}
public void checkClosed() throws SQLException {throw new SQLException("ResultSet.checkClosed() unsupported");}
}
// ResultSetAdapter를 상속받은 JDBCResultSet
public class JDBCResultSet extends ResultSetAdapter
{
private final Cursor cursor;
private static final NumberFormat format =
NumberFormat.getInstance();
/** Wrap a result set around a Cursor. The cursor
* should never have been advanced; just pass this constructor
* the return value from {@link Table#rows}.
*/
public JDBCResultSet(Cursor cursor) throws SQLException
{
this.cursor = cursor;
}
public boolean next()
{ return cursor.advance();
}
public String getString(String columnName) throws SQLException
{ try
{ Object contents = cursor.column(columnName);
return (contents==null) ? null : contents.toString();
}
catch( IndexOutOfBoundsException e )
{ throw new SQLException("column "+columnName+" doesn't exist" );
}
}
public double getDouble(String columnName) throws SQLException
{ try
{ String contents = getString(columnName);
return (contents == null)
? 0.0
: format.parse( contents ).doubleValue()
;
}
catch( ParseException e )
{ throw new SQLException("field doesn't contain a number");
}
}
public int getInt(String columnName) throws SQLException
{ try
{ String contents = getString(columnName);
return (contents == null)
? 0
: format.parse( contents ).intValue()
;
}
catch( ParseException e )
{ throw new SQLException("field doesn't contain a number");
}
}
public long getLong(String columnName) throws SQLException
{ try
{ String contents = getString(columnName);
return (contents == null)
? 0L
: format.parse( contents ).longValue()
;
}
catch( ParseException e )
{ throw new SQLException("field doesn't contain a number");
}
}
public void updateNull(String columnName )
{ cursor.update(columnName, null );
}
public void updateDouble(String columnName, double value)
{ cursor.update(columnName, format.format(value) );
}
public void updateInt(String columnName, long value)
{ cursor.update(columnName, format.format(value) );
}
public ResultSetMetaData getMetaData() throws SQLException
{ return new JDBCResultSetMetaData(cursor);
}
}
- Coursor 와 java.sql.ResultSet는 적어도 핵심관점에서는 차이가 없다, 또한 JDBCResultSet class는 Cursor 객채를 래핑하고 있기 때문에 Coursor 객체가 인터페이스를 구현하고 있는 것처럼 보일 수도 있다. 하지만 JDBCResultSet은 Cursor(Adaptee)가 Taget 인터페이스(java.sql.ResultSet)를 구현하고 있는 것처럼 보이도록 하는 Adapter이다.
public final class ArrayIterator implements Iterator
{
private int position = 0;
private final Object[] items;
public ArrayIterator(Object[] items){ this.items = items; }
public boolean hasNext()
{
return ( position < items.length );
}
public Object next()
{
if( position >= items.length )
throw new NoSuchElementException();
return items[ position++ ];
}
public void remove()
{
throw new UnsupportedOperationException(
"ArrayIterator.remove()");
}
/** Not part of the Iterator interface, returns the data
* set in array form. Modifying the returned array will
* not affect the iteration at all.
*/
public Object[] toArray()
{
return (Object[]) items.clone();
}
}
Arrayiterator 클래스(Adapter)는 배열(Adaptee)이 Iterator 인터페이스를 구현하고 있는 것 처럼 만들어 주기 때문에 배열을 Iterator를 통해 접근할 수 있게 해준다.
Bridge 패턴 VS Adapter 패턴
Bridge : 서브시스템들을 분리시키는 거 , 대규모
Adapter: 어떤 클래스를 이 클래스가 구현하고 있지 않은 인터페이스를 사용하여 작성한 프로그램에 적용시키기 위한 것, 소규모
Decorator 패턴 VS Adapter 패턴
Decorator : 어떤 클래스의 메소드를 행위를 상속(Extends)을 하지 않고 변경시키는 것
구조 측면에서 보자면 항상 자신이 데코레이팅하는 객체와 같은 인터페이스를 구현한다.
Adapter : 대부분의 경우 래핑되는 객체의 인터페이스를 구현하지 않는다.
- Command pattern과 비슷하다는 생각이 들어서 찾아본 검색 결과 후 답변
The Command
design pattern is used to solve problems like:
- How can an object be configured (customized) with a request?
- And how can the request be (ex)changed dynamically at run-time?
The point of Command
is to decouple a request from its invoker and encapsulate it in a separate object (Command interface).
Invoker then delegates a request to a command object dynamically.
The Adapter
design pattern (object adapter) is used to solve problems like:
- How can an object be accessed that has an incompatible interface
without changing existing interfaces?
The point of Adapter
is to work through a separate object that adapts an incompatible interface, i.e., that implements our needed interface (Target) in terms of (by delegating to) the incompatible interface.
The Command
pattern is more similar to the Strategy
pattern, which decouples an algorithm from its context and encapsulates it in a separate object (Strategy).
- Can we say the two patterns have the same implementation but different aims ? Maybe the implementation of the Adapter (object adapter) is somewhat easier: The Adapter pattern implements an existing interface (Target). Clients refer to this interface and needn't to be changed. The Command pattern defines a new interface (Command) and implements different requests. Clients must be designed/implemented/changed so that they delegate a request to one of different command objects. |