構造設計モード(1)-アダプタモード、ブリッジモード、複合モード
70847 ワード
アダプタモード
コンセントのことをよく話します.110 vを220 vに挿入するか、逆に互換性のあるアダプタを使用します.
既存のコードをクライアントが使用するインタフェースの実装体のモードに変換する
->クライアントの使用インタフェースに従わない既存のコードを再利用できます.
public interface UserDetails {
String getUsername();
String getPassword();
}
public interface UserDetailsService {
UserDetails loadUser(String username);
}
public class LoginHandler {
UserDetailsService userDetailsService;
public LoginHandler(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
public String login(String username, String password) {
UserDetails userDetails = userDetailsService.loadUser(username);
if (userDetails.getPassword().equals(password)) {
return userDetails.getUsername();
} else {
throw new IllegalArgumentException();
}
}
}
クライアントコード簡単なログイン処理ロジック.他のアプリケーションも再利用できます.
ターゲットコード
public class Account {
private String name;
private String password;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
public class AccountService {
public Account findAccountByUsername(String username) {
Account account = new Account();
account.setName(username);
account.setPassword(username);
account.setEmail(username);
return account;
}
public void createNewAccount(Account account) {
}
public void updateAccount(Account account) {
}
}
Adapteeに対応するコード、電子メールを受信しない、電話番号を受信するなど、異なる構成が可能です.(アプリケーションによって異なる場合があります.)public class AccountUserDetails implements UserDetails {
private Account account;
public AccountUserDetails(Account account) {
this.account = account;
}
@Override
public String getUsername() {
return account.getName();
}
@Override
public String getPassword() {
return account.getPassword();
}
}
public class AccountUserDetailsService implements UserDetailsService { //맞춰줘야되는 타겟 인터페이스 구현
private AccountService accountService; // 어댑티에 해당되는 코드사용
public AccountUserDetailsService(AccountService accountService) {
this.accountService = accountService;
}
@Override
public UserDetails loadUser(String username) {
return new AccountUserDetails(accountService.findAccountByUsername(username));
}
}
アダプタが作成されます. public static void main(String[] args) {
AccountService accountService = new AccountService();
UserDetailsService userDetailsService = new AccountUserDetailsService(accountService);
LoginHandler loginHandler = new LoginHandler(userDetailsService);
String login = loginHandler.login("youngjin", "940505");
System.out.println(login);
}
既存のコードに触れず、アダプタのみが追加されました.
弱いターゲットや適応性だけでコードを変更することはできません.外部ライブラリは非常に役に立つかもしれません.
コードを直接修正できると言ったら
Account Implements UserDetails(ターゲットインタフェースを直接実装)
長所
=>OCPに近い特性
=>SRPに近い特性
=>インタフェースを実装するために既存のコードを変更することは、
SRP(単一責任原則)の立場から見ると、区分等級は対象原則に近い
使用例
Java
public static void main(String[] args) {
// collections
List<String> strings = Arrays.asList("a", "b", "c"); // 배열을 리스트로 변환
Enumeration<String> enumeration = Collections.enumeration(strings); // Enumeration = 어댑터 strings = 어댑티 enumberration=타겟겟 ArrayList<String> list = Collections.list(enumeration);
// io
try(InputStream is = new FileInputStream("input.txt");
// String을줫지만 타겟인터페이스인 InputStream에 맞춰서 나옴
InputStreamReader isr = new InputStreamReader(is);
// InputStream을줫지만 InputStreamReader 를 줬다.
BufferedReader reader = new BufferedReader(isr)) {
while(reader.ready()) {
System.out.println(reader.readLine());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
SpringではHandlerアダプタでも使えます.ブリッジパターン
抽象=高度な抽象論理
これらのベンチクラスが継承されると、抽象概念はより多くの変形と異なる構造に拡張されます.
実装=ステータス、アクション、プラットフォーム固有コード
public interface Champion extends Skin {
void move();
void skillQ();
void skillW();
void skillE();
void skillR();
}
public class KDA아리 implements Champion {
@Override
public void move() {
System.out.println("KDA 아리 move");
}
@Override
public void skillQ() {
System.out.println("KDA 아리 Q");
}
@Override
public void skillW() {
System.out.println("KDA 아리 W");
}
@Override
public void skillE() {
System.out.println("KDA 아리 E");
}
@Override
public void skillR() {
System.out.println("KDA 아리 R");
}
@Override
public String getName() {
return null;
}
}
もし私が新しいチャンピオンを追加したら?あるいは新しい肌を追加したら?
public class 정복자아리 implements Champion {
@Override
public void move() {
System.out.println("정복자 아리 move");
}
@Override
public void skillQ() {
System.out.println("정복자 아리 Q");
}
@Override
public void skillW() {
System.out.println("정복자 아리 W");
}
@Override
public void skillE() {
System.out.println("정복자 아리 E");
}
@Override
public void skillR() {
System.out.println("정복자 아리 R");
}
@Override
public String getName() {
return null;
}
}
public static void main(String[] args) {
Champion kda아리 = new KDA아리();
kda아리.skillQ();
kda아리.skillR();
}
新しい征服者アリの皮膚があれば階層が大きくなり、Childクラスを作成する過程には重複コードが多く、他のクラスと差が少ないような気がします.
public interface Skin {
String getName();
}
public class DefaultChampion implements Champion {
private Skin skin; // 스킨인터페이스 사용
private String name;
public DefaultChampion(Skin skin, String name) {
this.skin = skin;
this.name = name;
}
@Override
public void move() {
System.out.printf("%s %s move\n", skin.getName(), this.name);
}
@Override
public void skillQ() {
System.out.printf("%s %s Q\n", skin.getName(), this.name);
}
@Override
public void skillW() {
System.out.printf("%s %s W\n", skin.getName(), this.name);
}
@Override
public void skillE() {
System.out.printf("%s %s E\n", skin.getName(), this.name);
}
@Override
public void skillR() {
System.out.printf("%s %s R\n", skin.getName(), this.name);
}
@Override
public String getName() {
return null;
}
}
チャンピオンを増やしたい?public class 아리 extends DefaultChampion {
public 아리(Skin skin) {
super(skin, "아리");
}
}
public class 아칼리 extends DefaultChampion{
public 아칼리(Skin skin) {
super(skin, "아칼리");
}
}
肌作りたい?public class KDA implements Skin{
@Override
public String getName() {
return "KDA";
}
}
public class PoolParty implements Skin {
@Override
public String getName() {
return "PoolParty";
}
}
これがモデルの核心です.現在の階層のみを拡張し、他の階層には触れません. public static void main(String[] args) {
Champion kda아리 = new 아리(new KDA());
kda아리.skillQ();
kda아리.skillW();
Champion poolParty아리 = new 아리(new PoolParty());
poolParty아리.skillR();
poolParty아리.skillW();
}
クライアントコードにもインタフェースが使用されています.(抽象部分)
ブリッジパターン
長所
=>OCP原則達成
短所
ブリッジモードの使用例
JDBC
Class.forName ("org.h2.Driver");
try (Connection conn = DriverManager.getConnection ("jdbc:h2:mem:~/test", "sa","")) {
String sql = "CREATE TABLE ACCOUNT " +
"(id INTEGER not NULL, " +
" email VARCHAR(255), " +
" password VARCHAR(255), " +
" PRIMARY KEY ( id ))";
Statement statement = conn.createStatement();
statement.execute(sql);
// PreparedStatement statement1 = conn.prepareStatement(sql);
// ResultSet resultSet = statement.executeQuery(sql);
} catch (SQLException e) {
throw new RuntimeException(e);
}
jdbcコードの一部これはResultSet、Statement、Connectionブリッジモードで抽象化することに相当します.
具体的なコードはDriver部分です.
java.sql.driverのいずれかのorg.h2.Driverを持ってきました.
複合モード
グループ全体と単一のグループを同時に処理できる540 ner
public static void main(String[] args) {
Item doranBlade = new Item("도란검", 450);
Item healPotion = new Item("체력 물약", 50);
Bag bag = new Bag();
bag.add(doranBlade);
bag.add(healPotion);
Client client = new Client();
client.printPrice(doranBlade);
client.printPrice(bag);
}
private void printPrice(Item item) {
System.out.println(item.getPrice());
}
private void printPrice(Bag bag) {
int sum = bag.getItems().stream().mapToInt(Item::getPrice).sum();
System.out.println(sum);
}
クライアントの場合、かばんの中の品物の値段を合わせて印刷したいです.
クライアントが多すぎることを知っておく必要があります
クライアントコードのポイント、
かばんの中にかばんが入っています.ちょっと待ってください.
コンポーネントと呼ばれるインタフェースを定義します.
public interface Component {
int getPrice();
}
重要なのは、汎用操作をインタフェースに配置する必要があることです.public class Item implements Component {
private String name;
private int price;
public Item(String name, int price) {
this.name = name;
this.price = price;
}
@Override
public int getPrice() {
return this.price;
}
}
インタフェースサポートの再構成方法getPrice()public class Bag implements Component {
private List<Component> components = new ArrayList<>();
public void add(Component component) {
components.add(component);
}
public List<Component> getComponents() {
return components;
}
@Override
public int getPrice() {
return components.stream().mapToInt(Component::getPrice).sum();
}
}
BagはLeafを参照せずにコンポーネントを参照する必要があります.クライアントが多すぎることを知る必要はありません.引合の責任者がBagに来ました.
public class Client {
public static void main(String[] args) {
Item doranBlade = new Item("도란검", 450);
Item healPotion = new Item("체력 물약", 50);
Bag bag = new Bag();
bag.add(doranBlade);
bag.add(healPotion);
Client client = new Client();
client.printPrice(doranBlade);
client.printPrice(bag);
}
private void printPrice(Component component) {
// 내가사용하는 타입의 변수들은 가능한한 추상적 인터페이스를 쓰는것이 좋은영향을 준다.
System.out.println(component.getPrice());
}
}
私が使用しているタイプの変数は、できるだけ抽象的なインタフェースを使用することが望ましい.(printPriceのコンポーネントパラメータなど)
クライアントが価格の具体的な情報をどのように取得するか分からないのも関係ありません.
複合モードの利点
=>クライアントの場合、新しいタイプのLeafまたはComponentが追加されても、クライアントコードは変更されません.
OCP原則
短所
=>もし副作用があったら、私は今デザインモードに依存していますか?他の方法はもっといいですか?
複合パターンの使用例
public static void main(String[] args) {
JFrame frame = new JFrame();
JTextField textField = new JTextField();
textField.setBounds(200, 200, 200, 40);
frame.add(textField);
JButton button = new JButton("click");
button.setBounds(200, 100, 60, 40);
button.addActionListener(e -> textField.setText("Hello Swing"));
frame.add(button);
frame.setSize(600, 400);
frame.setLayout(null);
frame.setVisible(true);
}
これはジャワのスイングです.フレームスペースにボタンやテキストスペースなどを追加できます.
JFrameはCompositeに相当し、Jbutton、JTextFeildはLeafの構造である.
Reference
この問題について(構造設計モード(1)-アダプタモード、ブリッジモード、複合モード), 我々は、より多くの情報をここで見つけました https://velog.io/@dudwls0505/구조-디자인패턴1-어댑터-패턴テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol