디자인 패턴(Design Pattern)은 대부분의 사람들에게 알려져 있는, 반복적으로 사용되는 코드 디자인 경험을 분류하고 정리한 집합입니다.
디자인 패턴은 3가지 유형으로 나누어져 총 23가지 유형이 있습니다.
홍양, 루키튜토리얼 등의 기사를 참고하여 작성하였습니다. 오류가 있으면 수정해 주시기 바랍니다. 침해된 내용이 있으면 저에게 연락하여 삭제하시기 바랍니다.
1. 디자인 패턴 관찰자 패턴(Observer Pattern) 위챗 공공 서비스를 예로 들어
2. 디자인 패턴 팩토리 패턴(Factory Pattern)은 로지아모 판매에서 시작됩니다
3. 디자인 패턴 싱글턴 디자인 패턴(Singleton Pattern) 완전 분석
4. 디자인 패턴 전략 패턴(Strategy Pattern)은 롤 게임을 배경으로 한다.
5. 디자인 패턴 Adapter Pattern (Adapter Pattern) 휴대폰 충전기를 예로 들어보겠습니다.
6. 스마트 가전을 관리하는 디자인 패턴 명령 패턴
7. 디자인 패턴 데코레이터 패턴이 여러분을 전설의 세계로 안내합니다.
8. 디자인 모드, 외관 모드(Facade Pattern) 원클릭 동영상 모드
9. 디자인 패턴 템플릿 메소드 패턴은 프로그래머의 하루를 보여준다
10. 디자인 패턴 상태 패턴(State Pattern) 자판기를 예로 들어보자
11. 디자인 패턴 빌더 패턴(Builder Pattern) 자동차를 만드는 것과 자동차를 사는 것을 예로 들어보자
12. 디자인 패턴 프로토타입 패턴(Prototype Pattern) 여러 모양을 얻는 것을 예로 들어보자
13. 디자인 패턴 플라이웨이트 패턴(Flyweight Pattern)은 무작위로 여러 모양을 얻는 것을 예로 들어봅니다.
14. 디자인 패턴 프록시 패턴(Proxy Pattern) 디스크에서 사진을 얻는 것을 예로 들어보자
15. 디자인 패턴 Bridge Pattern (Bridge Pattern) 다양한 색상의 원을 예로 그려봅니다.
16. 디자인 패턴 조합 패턴(Composite Pattern) 직원 계층 구조 생성 및 인쇄를 예로 들어보자
17. 디자인 패턴 Iterator Pattern (Iterator Pattern) 이름을 인쇄하기 위해 반복자를 사용하는 예를 들어보자.
18. 디자인 패턴 중재자 패턴(Mediator Pattern) 공개 채팅방을 예로 들면
19. 디자인 패턴 Memento Pattern (Memento Pattern) 메멘토를 예로 들어보자
20. 디자인 패턴 Interpreter Pattern (Interpreter Pattern) 문장을 설명하는 것을 예로 들어보자
21. 디자인 패턴 Chain of Responsibility Pattern(Chain of Responsibility Pattern) Android Studio에서 인쇄 로그를 예로 들어 보겠습니다.
22. 디자인 패턴 Visitor Pattern (Visitor Pattern) 컴퓨터의 구성요소를 표시하는 것을 예로 들어보자
- 관찰자
- 공장
- 하나씩 일어나는 것
- 전략
- 어댑터
- 명령
- 데코레이터
- 정면
- 템플릿 방법
- 상태
- 빌더
- 원기
- 플라이급
- 대리
- 다리
- 합성물
- 반복자
- 중재인
- 기념물
- 책임의 사슬
- 방문객
개체 간의 일대다 종속성을 정의하여 개체가 변경되면 모든 종속성이 통보되고 자동으로 업데이트됩니다.
JDK나 Andorid에는 XXXView.addXXXListenter와 같은 관찰자 패턴을 구현하는 곳이 많이 있습니다. 물론 관찰자 패턴은 일대다 관계이므로 XXXView.setOnXXXListener가 반드시 관찰자 패턴일 필요는 없으며 setXXXListener의 경우 1과 1 사이의 관계는 콜백이라고 불러야 합니다.
특수 인터페이스: Subject.java;
/**
* 注册一个观察者
*/
public void registerObserver ( Observer observer );
/**
* 移除一个观察者
*/
public void removeObserver ( Observer observer );
/**
* 通知所有观察者
*/
public void notifyObservers ();
3D 서비스 계정 구현 클래스: ObjectFor3D.java
@ Override
public void registerObserver ( Observer observer ) {
observers . add ( observer );
}
@ Override
public void removeObserver ( Observer observer ) {
int index = observers . indexOf ( observer );
if ( index >= 0 ) {
observers . remove ( index );
}
}
@ Override
public void notifyObservers () {
for ( Observer observer : observers ) {
observer . update ( msg );
}
}
/**
* 主题更新信息
*/
public void setMsg ( String msg ) {
this . msg = msg ;
notifyObservers ();
}
모든 관찰자는 다음 인터페이스를 구현해야 합니다: Observer.java
public ObserverUser1 ( Subject subject ) {
subject . registerObserver ( this );
}
@ Override
public void update ( String msg ) {
Log . e ( "-----ObserverUser1 " , "得到 3D 号码:" + msg + ", 我要记下来。" );
}
최종 테스트: ObserverActivity.java
// 创建服务号
objectFor3D = new ObjectFor3D ();
// 创建两个订阅者
observerUser1 = new ObserverUser1 ( objectFor3D );
observerUser2 = new ObserverUser2 ( objectFor3D );
// 两个观察者,发送两条信息
objectFor3D . setMsg ( "201610121 的3D号为:127" );
objectFor3D . setMsg ( "20161022 的3D号为:000" );
이 패턴의 계열을 간략하게 나열해 보겠습니다.
1. 정적 공장 모드
2. 간단한 공장 모드(상점에서 Roujiamo 구매)
public RoujiaMo creatRoujiaMo ( String type ) {
RoujiaMo roujiaMo = null ;
switch ( type ) {
case "Suan" :
roujiaMo = new ZSuanRoujiaMo ();
break ;
case "La" :
roujiaMo = new ZLaRoujiaMo ();
break ;
case "Tian" :
roujiaMo = new ZTianRoujiaMo ();
break ;
default : // 默认为酸肉夹馍
roujiaMo = new ZSuanRoujiaMo ();
break ;
}
return roujiaMo ;
}
3. 팩토리 메소드 모델(브랜치 개설)
Roujia MoStore를 생성하기 위한 추상 메소드 제공: RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo ( String type );
추상 메소드의 특정 구현: XianRoujiaMoStore.java
브랜치는 여전히 단순 팩토리 모델인 XianSimpleRoujiaMoFactory.java를 사용합니다.
4. 추상 팩토리 패턴(공식 원자재 사용)
/**
* 准备工作
*/
public void prepare ( RoujiaMoYLFactory roujiaMoYLFactory ) {
Meet meet = roujiaMoYLFactory . creatMeet ();
YuanLiao yuanLiao = roujiaMoYLFactory . creatYuanLiao ();
Log . e ( "---RoujiaMo:" , "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:" + meet + "yuanLiao:" + yuanLiao );
}
싱글톤 모드는 주로 여러 인스턴스 생성으로 인한 리소스 낭비를 피하기 위한 것이며, 여러 인스턴스는 여러 호출로 인해 쉽게 잘못된 결과로 이어질 수 있습니다. 싱글톤 모드를 사용하면 전체 애플리케이션에 하나의 인스턴스만 존재하도록 보장할 수 있습니다 .
정의: 객체의 고유성을 보장하려면 세 단계만 필요합니다.
정의 비교:
Hungry Han 스타일 [사용 가능]: SingletonEHan.java
게으른 Han 스타일을 포함합니다[이중 확인 잠금 권장]: SingletonLanHan.java
private SingletonLanHan () {}
private static SingletonLanHan singletonLanHanFour ;
public static SingletonLanHan getSingletonLanHanFour () {
if ( singletonLanHanFour == null ) {
synchronized ( SingletonLanHan . class ) {
if ( singletonLanHanFour == null ) {
singletonLanHanFour = new SingletonLanHan ();
}
}
}
return singletonLanHanFour ;
}
전략 패턴: 알고리즘 계열을 정의하고 이를 별도로 캡슐화하여 상호 교환이 가능하도록 합니다. 이 패턴을 사용하면 알고리즘을 사용하는 고객과 독립적으로 알고리즘을 변경할 수 있습니다.
RoleA roleA = new RoleA ( "---A" );
roleA . setiDisplayBehavior ( new DisplayYZ ())
. setiAttackBehavior ( new AttackXL ())
. setiDefendBehavior ( new DefendTMS ())
. setiRunBehavior ( new RunJCTQ ());
roleA . display (); // 样子
roleA . attack (); // 攻击
roleA . run (); // 逃跑
roleA . defend (); // 防御
정의: 클래스의 인터페이스를 클라이언트가 예상하는 다른 인터페이스로 변환합니다. 어댑터를 사용하면 호환되지 않는 인터페이스를 가진 클래스가 서로 협력할 수 있습니다. 어댑터의 기능이 하나의 인터페이스를 다른 인터페이스로 변환하는 것이라고 말하면 이 정의는 괜찮습니다.
충전기를 예로 들어보겠습니다. 휴대폰 충전기는 일반적으로 5V 정도입니다. 중국의 가정용 AC 전압은 220V이므로 휴대폰 충전에는 어댑터(감압기)가 필요합니다.
휴대폰: Mobile.java
전화기는 5V 전압을 제공하는 인터페이스인 V5Power.java를 사용합니다.
우리가 가지고 있는 것은 220V 가정용 AC입니다: V220Power.java
220V를 5V로 변환하는 기능을 완성하는 어댑터 : V5PowerAdapter.java
최종 테스트: 전화 충전:
Mobile mobile = new Mobile ();
V5Power v5Power = new V5PowerAdapter ( new V200Power ());
mobile . inputPower ( v5Power );
정의: 다른 개체가 다른 요청, 대기열 또는 로그를 사용하여 매개변수화될 수 있도록 "요청"을 개체로 캡슐화합니다. 명령 모드는 실행 취소할 수 있는 작업도 지원합니다. (단순화: 요청을 객체로 캡슐화하고 작업 요청자와 작업 실행자를 분리합니다.)
QuickCommand quickCloseCommand = new QuickCommand ( new Command []{ new LightOffCommand ( light ), new ComputerOffCommand ( computer ), new DoorCloseCommand ( door )});
controlPanel . setCommands ( 6 , quickOpenCommand );
controlPanel . keyPressed ( 6 );
controlPanel . setCommands ( 0 , new DoorOpenCommand ( door )); // 开门
controlPanel . keyPressed ( 0 );
데코레이터 패턴: 기능을 확장하기 위해 데코레이터는 통합에 대한 보다 유연한 대안을 제공하여 개체에 책임을 동적으로 연결합니다.
데코레이터 패턴이 적용되는 위치를 간략하게 설명하겠습니다. 클래스를 디자인할 때 이 클래스에 몇 가지 보조 기능을 추가해야 하며 이때 데코레이터 패턴이 시작됩니다. 이제 시간이다. 이는 또한 원칙을 반영합니다. 클래스는 확장에 개방적이고 수정에는 폐쇄되어야 합니다.
요구 사항: 게임의 장비 시스템을 설계합니다. 기본 요구 사항은 다양한 보석을 내장한 후 각 장비의 공격력과 설명을 계산할 수 있어야 한다는 것입니다.
1. 장비의 슈퍼 클래스: IEquip.java
2. 각 장비의 구현 등급:
3. 장식의 슈퍼 클래스(장식도 장비에 속함): IEquipDecorator.java
4. 장식 구현 클래스:
5. 최종 테스트: 공격력 계산 및 설명 보기:
Log . e ( "---" , "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: " );
IEquip iEquip = new RedGemDecorator ( new RedGemDecorator ( new BlueGemDecorator ( new ShoeEquip ())));
Log . e ( "---" , "攻击力:" + iEquip . caculateAttack ());
Log . e ( "---" , "描述语:" + iEquip . description ());
정의: 하위 시스템의 인터페이스 그룹에 액세스하기 위한 통합 인터페이스를 제공합니다. 외관은 하위 시스템을 더 쉽게 사용할 수 있도록 높은 수준의 인터페이스를 정의합니다. 실제로 고객의 편의를 위해 작업 그룹이 메서드로 캡슐화됩니다.
수요: 영화 보는 걸 더 좋아해서 프로젝터도 사고, 컴퓨터도 사고, 스테레오도 사고, 방 조명도 디자인하고, 팝콘 기계도 사고, 영화를 보고 싶을 때 원클릭 시청과 원클릭 종료가 필요해요. .
각 장치 클래스에 대한 스위치 및 기타 작업:
예: 팝콘 기계: PopcornPopper.java
시네마 클래스: HomeTheaterFacade.java
/**
* 一键观影
*/
public void watchMovie () {
computer . on ();
light . down ();
popcornPopper . on ();
popcornPopper . makePopcorn ();
projector . on ();
projector . open ();
player . on ();
player . make3DListener ();
}
최종 테스트: 원클릭 영화 보기:
new HomeTheaterFacade ( computer , light , player , popcornPopper , projector ). watchMovie ();
정의: 알고리즘의 뼈대를 정의하고 일부 단계를 하위 클래스로 연기합니다. 템플릿 방법을 사용하면 하위 클래스가 알고리즘 구조를 변경하지 않고도 알고리즘 단계를 재정의할 수 있습니다.
요구 사항: 간략하게 설명: 우리 회사에는 프로그래머, 테스터, HR, 프로젝트 관리자 등이 있습니다. 아래에서는 템플릿 방법 모드를 사용하여 모든 직원의 작업 상태를 기록합니다.
템플릿 메서드 패턴의 세 가지 역할 유형
1. 구체적인 방법
2. 추상 방법
3. 후크 방식
워커 슈퍼클래스: Worker.java
// 具体方法
public final void workOneDay () {
Log . e ( "workOneDay" , "-----------------work start----------------" );
enterCompany ();
work ();
exitCompany ();
Log . e ( "workOneDay" , "-----------------work end----------------" );
}
// 工作 抽象方法
public abstract void work ();
// 钩子方法
public boolean isNeedPrintDate () {
return false ;
}
private void exitCompany () {
if ( isNeedPrintDate ()) {
Log . e ( "exitCompany" , "---" + new Date (). toLocaleString () + "--->" );
}
Log . e ( "exitCompany" , name + "---离开公司" );
}
프로그래머 구현 클래스(시간 알 수 있음): ITWorker.java
/**
* 重写父类的此方法,使可以查看离开公司时间
*/
@ Override
public boolean isNeedPrintDate () {
return true ;
}
최종 테스트:
모두가 어떻게 작업하는지 확인하세요.
QAWorker qaWorker = new QAWorker ( "测试人员" );
qaWorker ();
HRWorker hrWorker = new HRWorker ( "莉莉姐" );
hrWorker . workOneDay ();
...
프로그래머가 언제 회사를 떠났는지 확인하세요.
ITWorker itWorker = new ITWorker ( "jingbin" );
itWorker . workOneDay ();
정의: 내부 상태가 변경될 때 개체의 동작을 변경하여 개체가 해당 클래스를 수정한 것처럼 보이도록 합니다.
정의가 다시 흐려지기 시작했습니다. 객체의 내부 상태가 변경되면 상태 변경에 따라 동작도 변경되는 것처럼 보입니다.
요구사항: 자판기를 예로 들어보겠습니다. (동전 투입 및 미 투입 상태, 동전 투입 및 반납 방법 등이 있습니다.)
개선할 자판기의 초기 구현: VendingMachine.java
개선된 자동 판매기(더 유연함): VendingMachineBetter.java
// 放钱
public void insertMoney () {
currentState . insertMoney ();
}
// 退钱
public void backMoney () {
currentState . backMoney ();
}
// 转动曲柄
public void turnCrank () {
currentState . turnCrank ();
if ( currentState == soldState || currentState == winnerState ) {
currentState . dispense (); //两种情况会出货
}
}
// 出商品
public void dispense () {
Log . e ( "VendingMachineBetter" , "---发出一件商品" );
if ( count > 0 ) {
count --;
}
}
// 设置对应状态
public void setState ( State state ) {
this . currentState = state ;
}
상태 인터페이스: State.java
상태에 해당하는 인터페이스 구현 클래스:
향상된 자동판매기 테스트:
// 初始化售货机,且里面有3个商品
VendingMachineBetter machineBetter = new VendingMachineBetter ( 3 );
machineBetter . insertMoney ();
machineBetter . turnCrank ();
구성 모드는 객체 생성 모드입니다. 구성 모드는 제품의 내부 표현을 제품 생산 프로세스에서 분리할 수 있으므로 구성 프로세스는 다양한 내부 표현을 사용하여 제품 개체를 생성할 수 있습니다.
요구 사항: 사용자는 자동차를 구입하기 위해 자동차 판매점에 갑니다.
분석: 자동차 매장은 각 사용자의 요구에 따라 해당 자동차를 추출합니다.
빌더 슈퍼클래스: 빌더
public abstract class Builder {
public abstract void setPart ( String name , String type );
public abstract Product getProduct ();
}
Builder 해당 구현 클래스: ConcreteBuilder
public class ConcreteBuilder extends Builder {
private Product product = new Product ();
@ Override
public void setPart ( String name , String type ) {
product . setName ( name );
product . setType ( type );
}
@ Override
public Product getProduct () {
return product ;
}
}
매장 관리자가 차를 픽업합니다.
// 店长
Director director = new Director ();
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
Product product = director . getBProduct ();
// 展示汽车信息
product . showProduct ();
프로토타입 패턴은 성능을 보장하면서 반복되는 객체를 생성하는 데 사용됩니다. 이러한 유형의 디자인 패턴은 객체를 생성하는 최적의 방법을 제공하는 생성 패턴입니다.
이 패턴은 현재 객체의 복제본을 만드는 데 사용되는 프로토타입 인터페이스를 구현합니다. 이 모드는 객체를 직접 생성하는 비용이 상대적으로 높을 때 사용됩니다. 예를 들어, 비용이 많이 드는 데이터베이스 작업 후에 개체를 생성해야 합니다. 객체를 캐시하고, 다음 요청 시 객체의 복제본을 반환하고, 필요할 때 데이터베이스를 업데이트하여 데이터베이스 호출을 줄일 수 있습니다.
여러 모양을 얻는 것을 예로 들면 다음과 같은 네 단계가 있습니다.
1. Cloneable 인터페이스를 구현하는 추상 클래스를 만듭니다. Shape(Cloneable 구현)
public abstract class Shape implements Cloneable {
private String id ;
protected String type ;
public abstract void draw ();
public String getId () {
return id ;
}
public void setId ( String id ) {
this . id = id ;
}
@ Override
public Object clone () {
Object object = null ;
try {
object = super . clone ();
} catch ( CloneNotSupportedException e ) {
Log . e ( "--" , e . getMessage ());
}
return object ;
}
}
2. 위의 추상 클래스를 확장하는 엔터티 클래스를 만듭니다. 원형, 직사각형, 정사각형
public class Circle extends Shape {
public Circle () {
type = "Circle" ;
}
@ Override
public void draw () {
Log . e ( "---" , "Inside Circle::draw() method." );
}
}
3. 데이터베이스에서 엔터티 클래스를 가져오고 이를 해시 테이블에 저장하는 클래스를 만듭니다. 셰이프캐시
public class ShapeCache {
private static Hashtable < String , Shape > shapeMap = new Hashtable < String , Shape >();
public static Shape getShape ( String shapeId ) {
Shape shapeCache = shapeMap . get ( shapeId );
return ( Shape ) shapeCache . clone ();
}
// 对每种形状都运行数据库查询,并创建该形状
// shapeMap.put(shapeKey, shape);
// 例如,我们要添加三种形状
public static void loadCache () {
Circle circle = new Circle ();
circle . setId ( "1" );
shapeMap . put ( circle . getId (), circle );
Rectangle rectangle = new Rectangle ();
rectangle . setId ( "2" );
shapeMap . put ( rectangle . getId (), rectangle );
Square square = new Square ();
square . setId ( "3" );
shapeMap . put ( square . getId (), square );
}
}
4. ShapeCache 클래스를 사용하여 Hashtable에 저장된 모양의 복제본을 얻습니다.
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache . loadCache ();
Shape shapeCache1 = ShapeCache . getShape ( "1" );
Shape shapeCache2 = ShapeCache . getShape ( "2" );
Shape shapeCache3 = ShapeCache . getShape ( "3" );
주로 메모리 사용량을 줄이고 성능을 향상시키기 위해 생성되는 개체 수를 줄이는 데 사용됩니다. 이러한 유형의 디자인 패턴은 객체 수를 줄여 애플리케이션에 필요한 객체 구조를 개선하는 방법을 제공하는 구조적 패턴입니다.
플라이웨이트 패턴은 동일한 유형의 기존 개체를 재사용하려고 시도하거나 일치하는 개체가 없으면 새 개체를 만듭니다. 서로 다른 위치에 20개의 원을 그리는 5개의 개체를 만들어 이 패턴을 보여 드리겠습니다. 사용할 수 있는 색상은 5가지뿐이므로 기존 Circle 객체를 확인하기 위해 color 속성을 사용합니다.
예를 들어 여러 모양을 무작위로 얻는 경우 다음 네 단계가 있습니다.
1. 인터페이스를 생성합니다.
public interface Shape {
void draw ();
}
2. 인터페이스를 구현하는 엔터티 클래스를 만듭니다.
public class Circle implements Shape {
private String color ;
private int x ;
private int y ;
private int radius ;
public Circle ( String color ) {
this . color = color ;
}
public void setX ( int x ) {
this . x = x ;
}
public void setY ( int y ) {
this . y = y ;
}
public void setRadius ( int radius ) {
this . radius = radius ;
}
@ Override
public void draw () {
Log . e ( "---" , "Circle: Draw() [Color : " + color
+ ", x : " + x + ", y :" + y + ", radius :" + radius );
}
}
3. 주어진 정보를 기반으로 엔터티 클래스의 객체를 생성하는 팩토리를 생성합니다.
public class ShapeFactory {
private static final HashMap < String , Shape > circleMap = new HashMap < String , Shape >();
public static Shape getShape ( String color ) {
Shape shape = circleMap . get ( color );
if ( shape == null ) {
shape = new Circle ( color );
circleMap . put ( color , shape );
Log . e ( "getShape" , "Creating circle of color : " + color );
}
return shape ;
}
}
4. 이 팩토리를 사용하여 색상 정보를 전달하여 엔터티 클래스의 개체를 얻습니다.
for ( int i = 0 ; i < 20 ; i ++) {
Circle circle = ( Circle ) ShapeFactory . getShape ( getRandomColor ());
circle . setX ( getRandomX ());
circle . setY ( getRandomY ());
circle . setRadius ( 100 );
circle . draw ();
}
한 클래스는 다른 클래스의 기능을 나타냅니다. 프록시 패턴에서는 외부 세계에 기능적 인터페이스를 제공하기 위해 기존 개체로 개체를 만듭니다. 메모리에 그러한 객체가 없으면 생성되고, 있으면 객체가 직접 반환되는 것으로 이해할 수 있습니다.
예를 들어 디스크에서 사진을 가져오는 경우 총 세 단계가 있습니다.
1. 인터페이스를 생성합니다.
public interface Image {
void display ();
}
2. 인터페이스를 구현하는 엔터티 클래스 RealImage를 만듭니다. 해당 프록시 클래스: ProxyImage.
public class RealImage implements Image {
private String fileName ;
public RealImage ( String fileName ) {
this . fileName = fileName ;
loadFromDisk ( fileName );
}
private void loadFromDisk ( String fileName ) {
Log . e ( "RealImage" , "loading " + fileName );
}
@ Override
public void display () {
Log . e ( "RealImage" , "Displaying " + fileName );
}
}
public class ProxyImage implements Image {
private String fileName ;
private RealImage realImage ;
public ProxyImage ( String fileName ) {
this . fileName = fileName ;
}
@ Override
public void display () {
if ( realImage == null ) {
realImage = new RealImage ( fileName );
}
realImage . display ();
}
}
3. 요청 시 ProxyImage를 사용하여 RealImage 클래스의 객체를 얻습니다.
Image image = new ProxyImage ( "test_10mb.png" );
// 第一次是new的,图像从磁盘加载
image . display ();
// 第二次取缓存,图像不需要从磁盘加载
image . display ();
브리지는 추상화와 구현을 분리하여 두 가지가 독립적으로 변경될 수 있도록 하는 데 사용됩니다. 이러한 유형의 디자인 패턴은 추상화와 구현 사이에 브리징 구조를 제공하여 분리하는 구조적 패턴입니다.
다양한 색상의 원 그리기를 예로 들면, 구현은 5단계로 나뉩니다.
1. 브리지 구현 인터페이스를 생성합니다.
public interface DrawAPI {
void drawCircle ( int radius , int x , int y );
}
2. DrawAPI 인터페이스를 구현하는 엔터티 브리지 구현 클래스를 만듭니다. 레드서클, 그린서클
public class RedCircle implements DrawAPI {
@ Override
public void drawCircle ( int radius , int x , int y ) {
Log . e ( "---" , "Drawing Circle[ color: red, radius: "
+ radius + ", x: " + x + ", " + y + "]" );
}
}
3. DrawAPI 인터페이스를 사용하여 Shape 추상 클래스를 생성합니다.
public abstract class Shape {
protected DrawAPI drawAPI ;
protected Shape ( DrawAPI drawAPI ) {
this . drawAPI = drawAPI ;
}
public abstract void draw ();
}
4. Shape 인터페이스를 구현하는 엔터티 클래스를 만듭니다.
public class Circle extends Shape {
private int x , y , radius ;
protected Circle ( int x , int y , int radius , DrawAPI drawAPI ) {
super ( drawAPI );
this . x = x ;
this . y = y ;
this . radius = radius ;
}
@ Override
public void draw () {
drawAPI . drawCircle ( radius , x , y );
}
}
5. Shape 및 DrawAPI 클래스를 사용하여 다양한 색상의 원을 그립니다.
// 画红圆
Circle circle = new Circle ( 10 , 10 , 100 , new RedCircle ()); s
circle . draw ();
// 画绿圆
Circle circle2 = new Circle ( 20 , 20 , 100 , new GreenCircle ());
circle2 . draw ();
부분-전체 패턴이라고도 하며 유사한 개체 그룹을 단일 개체로 처리하는 데 사용됩니다. 컴포지션 모드는 부분 및 전체 계층을 나타내는 데 사용되는 트리 구조에 따라 개체를 결합합니다. 이러한 유형의 디자인 패턴은 객체 그룹의 트리 구조를 생성하는 구조적 패턴입니다.
직원 계층 구조를 생성하고 인쇄하는 가장 작은 단위의 예를 들어보겠습니다.
1. Employee 개체 목록을 사용하여 Employee 클래스를 만듭니다.
public class Employee {
private String name ;
// 部门
private String dept ;
// 工资
private int salary ;
// 员工 list
private List < Employee > subordinates ;
public Employee ( String name , String dept , int salary ) {
this . name = name ;
this . dept = dept ;
this . salary = salary ;
this . subordinates = new ArrayList < Employee >();
}
public void add ( Employee e ) {
subordinates . add ( e );
}
public void remove ( Employee e ) {
subordinates . remove ( e );
}
public List < Employee > getSubordinates () {
return subordinates ;
}
@ Override
public String toString () {
return "Employee{" +
"name='" + name + ''' +
", dept='" + dept + ''' +
", salary=" + salary +
", subordinates=" + subordinates +
'}' ;
}
}
2. Employee 클래스를 사용하여 직원 계층 구조를 생성하고 인쇄합니다.
final Employee ceo = new Employee ( "John" , "CEO" , 30000 );
Employee headSales = new Employee ( "Robert" , "Head sales" , 20000 );
Employee headMarketing = new Employee ( "Michel" , "Head Marketing" , 20000 );
Employee clerk1 = new Employee ( "Laura" , "Marketing" , 10000 );
Employee clerk2 = new Employee ( "Bob" , "Marketing" , 10000 );
Employee salesExecutive1 = new Employee ( "Richard" , "Sales" , 10000 );
Employee salesExecutive2 = new Employee ( "Rob" , "Sales" , 10000 );
ceo . add ( headSales );
ceo . add ( headMarketing );
headSales . add ( salesExecutive1 );
headSales . add ( salesExecutive2 );
headMarketing . add ( clerk1 );
headMarketing . add ( clerk2 );
Log . e ( "---" , ceo . toString ());
// 打印
/*
* Employee{name='John', dept='CEO', salary=30000,
* subordinates=[Employee{name='Robert', dept='Head sales', salary=20000,
* subordinates=[
* Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]},
* Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]},
* Employee{name='Michel', dept='Head Marketing', salary=20000,
* subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]},
* Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]}
*/
Java 및 .Net 프로그래밍 환경에서 매우 일반적인 디자인 패턴입니다. 이 패턴은 컬렉션 개체의 기본 표현을 알지 못한 채 컬렉션 개체의 요소에 순차적으로 액세스하는 데 사용됩니다. 반복자 패턴은 동작 패턴입니다.
예를 들어 반복자를 사용하여 이름을 인쇄하면 총 세 단계가 있습니다.
1. 인터페이스를 생성합니다:
public interface Iterator {
public boolean hasNext ();
public Object next ();
}
public interface Container {
public Iterator getIterator ();
}
2. 컨테이너 인터페이스를 구현하는 엔터티 클래스를 만듭니다. 이 클래스에는 Iterator 인터페이스를 구현하는 내부 클래스 NameIterator가 있습니다.
public class NameRepository implements Container {
private String names [] = { "John" , "jingbin" , "youlookwhat" , "lookthis" };
@ Override
public Iterator getIterator () {
return new NameIterator ();
}
private class NameIterator implements Iterator {
int index ;
@ Override
public boolean hasNext () {
if ( index < names . length ) {
return true ;
}
return false ;
}
@ Override
public Object next () {
if ( hasNext ()) {
return names [ index ++];
}
return null ;
}
}
}
3. NameRepository를 사용하여 반복자를 가져오고 이름을 인쇄합니다.
NameRepository nameRepository = new NameRepository ();
for ( Iterator iterator = nameRepository . getIterator (); iterator . hasNext (); ) {
String name = ( String ) iterator . next ();
Log . e ( "---" , name );
/*
* /---: John
* /---: jingbin
* /---: youlookwhat
* /---: lookthis
*/
}
여러 개체와 클래스 간의 통신 복잡성을 줄이는 데 사용됩니다. 이 패턴은 일반적으로 서로 다른 클래스 간의 통신을 처리하고 느슨한 결합을 지원하는 중간 클래스를 제공하므로 코드를 더 쉽게 유지 관리할 수 있습니다. 중재자 모델은 행동 모델입니다.
공개 채팅방을 예로 들면 최소 단위 예시 단계는 다음과 같습니다.
1. 중개 클래스를 생성합니다.
public class CharRoom {
public static void showMessage ( User user , String message ) {
Log . e ( "---" , new Date (). toString ()
+ " [" + user . getName () + "] : " + message );
}
}
2. 사용자 클래스를 생성합니다.
public class User {
private String name ;
public User ( String name ) {
this . name = name ;
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public void sendMessage ( String message ) {
// 使用中介类
CharRoom . showMessage ( this , message );
}
}
3. 사용자 개체를 사용하여 이들 간의 통신을 표시합니다.
User jingbin = new User ( "jingbin" );
jingbin . sendMessage ( "Hi~ youlookwhat!" );
//---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!
User jingbin = new User ( "youlookwhat" );
jingbin . sendMessage ( "Hi~ jingbin!" );
//---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
적절한 시점에 복원할 수 있도록 개체의 특정 상태를 저장합니다. 메모 모드는 행동 모드입니다.
메모를 예로 들면 최소 단위 단계는 다음과 같습니다.
1. Memento 클래스를 생성합니다.
public class Memento {
private String state ;
public Memento ( String state ) {
this . state = state ;
}
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
}
2. Originator 클래스를 생성합니다.
public class Originator {
private String state ;
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
public Memento setSateToMemento () {
return new Memento ( state );
}
public String getStateFromMemento ( Memento memento ) {
return memento . getState ();
}
}
3. CareTaker 클래스를 생성합니다.
public class CareTaker {
private List < Memento > mementoList = new ArrayList < Memento >();
public void add ( Memento memento ) {
mementoList . add ( memento );
}
public Memento get ( int index ) {
return mementoList . get ( index );
}
}
4. CareTaker 및 Originator 개체를 사용하십시오.
// 管理者
CareTaker careTaker = new CareTaker ();
Originator originator = new Originator ();
originator . setState ( "State #1" );
originator . setState ( "State #2" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #3" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #4" );
Log . e ( "---" , "Current State: " + originator . getState ());
// 得到保存的状态
String fromMemento1 = originator . getStateFromMemento ( careTaker . get ( 0 ));
Log . e ( "---" , "First Saved State: " + fromMemento1 );
String fromMemento2 = originator . getStateFromMemento ( careTaker . get ( 1 ));
Log . e ( "---" , "Second Saved State: " + fromMemento2 );
/*
* /---: Current State: State #4
* /---: First Saved State: State #2
* /---: Second Saved State: State #3
*/
언어의 문법이나 표현을 평가하는 방법을 제공하며 행동 패턴입니다. 이 패턴은 특정 컨텍스트를 해석하는 표현식 인터페이스를 구현합니다. 이 모드는 SQL 구문 분석, 기호 처리 엔진 등에 사용됩니다.
예를 들어 문장을 설명하면 최소 단위 단계는 다음과 같습니다.
1. 표현식 인터페이스 Expression을 생성합니다.
public interface Expression {
public boolean interpreter ( String content );
}
2. 위 인터페이스를 구현하는 엔터티 클래스를 생성합니다. TerminalExpression, OrExpression, AndExpression.
public class TerminalExpression implements Expression {
private String data ;
public TerminalExpression ( String data ) {
this . data = data ;
}
@ Override
public boolean interpreter ( String content ) {
// 是包含判断
return content . contains ( data );
}
}
public class OrExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public OrExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) || expression2 . interpreter ( content );
}
}
public class AndExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public AndExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) && expression2 . interpreter ( content );
}
}
3. Expression 클래스를 사용하여 규칙을 생성하고 구문 분석합니다.
/**
* 规则:jingbin 和 youlookwhat 是男性
*/
public static Expression getMaleExpression () {
TerminalExpression jingbin = new TerminalExpression ( "jingbin" );
TerminalExpression youlookwhat = new TerminalExpression ( "youlookwhat" );
return new OrExpression ( jingbin , youlookwhat );
}
/**
* 规则:Julie 是一个已婚的女性
*/
public static Expression getMarriedWomanExpression () {
TerminalExpression julie = new TerminalExpression ( "Julie" );
TerminalExpression married = new TerminalExpression ( "Married" );
return new AndExpression ( julie , married );
}
Expression maleExpression = getMaleExpression ();
// jingbin is male: true
Log . e ( "---" , "jingbin is male: " + maleExpression . interpreter ( "jingbin" ));
Expression womanExpression = getMarriedWomanExpression ();
// Julie is married woman: true
Log . e ( "---" , "Julie is married woman: " + womanExpression . interpreter ( "Married Julie" ));
책임 체인 패턴은 요청에 대한 수신자 개체 체인을 생성합니다. 이 패턴은 요청 유형에 따라 요청의 발신자와 수신자를 분리합니다. 이러한 유형의 디자인 패턴은 행동 패턴입니다. 이 패턴에서는 일반적으로 각 수신기에 다른 수신기에 대한 참조가 포함됩니다. 객체가 요청을 처리할 수 없는 경우 동일한 요청을 다음 수신자에게 전달합니다.
Android Studio에서 로그 인쇄를 예로 들면 최소 단위 단계는 다음과 같습니다.
1. 추상 로거 클래스 AbstractLogger를 생성합니다.
public abstract class AbstractLogger {
public static int INFO = 1 ;
public static int DEBUG = 2 ;
public static int ERROR = 3 ;
protected int level ;
// 责任链中的下一个元素
protected AbstractLogger nextLogger ;
public void setNextLogger ( AbstractLogger nextLogger ) {
this . nextLogger = nextLogger ;
}
public void logMessage ( int level , String message ) {
if ( this . level <= level ) {
write ( message );
}
// 递归效果,不断调用下一级 logMessage
if ( nextLogger != null ) {
nextLogger . logMessage ( level , message );
}
}
protected abstract void write ( String message );
}
2. 로거 클래스를 확장하는 엔터티 클래스를 생성합니다.
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Standard Console::Logger " + message );
}
}
public class FileLogger extends AbstractLogger {
public FileLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "File::Logger " + message );
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Error Console::Logger " + message );
}
}
3. 다양한 유형의 로거를 생성합니다. 서로 다른 오류 수준을 제공하고 각 로거 내에서 다음 로거를 설정합니다. 각 로거의 다음 로거는 체인의 일부를 나타냅니다.
public static AbstractLogger getChainOfLoggers () {
ErrorLogger errorLogger = new ErrorLogger ( AbstractLogger . ERROR );
FileLogger fileLogger = new FileLogger ( AbstractLogger . DEBUG );
ConsoleLogger consoleLogger = new ConsoleLogger ( AbstractLogger . INFO );
errorLogger . setNextLogger ( fileLogger );
fileLogger . setNextLogger ( consoleLogger );
return errorLogger ;
}
AbstractLogger logger = getChainOfLoggers ();
// ---: Standard Console::Logger this is an information.
logger . logMessage ( AbstractLogger . INFO , "this is an information." );
// ---: File::Logger this is a debug level information.
// ---: Standard Console::Logger this is a debug level information.
logger . logMessage ( AbstractLogger . DEBUG , "this is a debug level information." );
// ---: Error Console::Logger this is a error level information.
// ---: File::Logger this is a error level information.
// ---: Standard Console::Logger this is a error level information.
logger . logMessage ( AbstractLogger . ERROR , "this is a error level information." );
방문자 패턴에서는 요소 클래스의 실행 알고리즘을 변경하는 방문자 클래스를 사용합니다. 이러한 방식으로 방문자가 변경됨에 따라 요소의 실행 알고리즘이 변경될 수 있습니다. 이러한 유형의 디자인 패턴은 행동 패턴입니다. 스키마에 따르면 방문자 개체가 요소 개체에 대한 작업을 처리할 수 있도록 요소 개체가 방문자 개체를 수락했습니다.
디스플레이 컴퓨터의 구성요소를 예로 들면, 주로 5단계로 구현됩니다.
1. 요소를 나타내는 인터페이스를 정의합니다.
public interface ComputerPart {
public void accept ( ComputerPartVisitor computerPartVisitor );
}
2. 위 클래스를 확장하는 엔터티 클래스를 만듭니다. 키보드, 모니터, 마우스, 컴퓨터
public class Computer implements ComputerPart {
private ComputerPart [] parts ;
public Computer () {
this . parts = new ComputerPart []{ new Mouse (), new Keyboard (), new Monitor ()};
}
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
for ( ComputerPart part : parts ) {
part . accept ( computerPartVisitor );
}
computerPartVisitor . visit ( this );
}
}
public class Mouse implements ComputerPart {
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
computerPartVisitor . visit ( this );
}
}
3. 방문자를 나타내는 인터페이스를 정의합니다.
public interface ComputerPartVisitor {
public void visit ( Computer computer );
public void visit ( Mouse mouse );
public void visit ( Keyboard keyboard );
public void visit ( Monitor monitor );
}
4. 위 클래스를 구현하는 엔터티 방문자를 만듭니다.
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@ Override
public void visit ( Computer computer ) {
Log . e ( "---" , "Displaying Computer." );
}
@ Override
public void visit ( Mouse mouse ) {
Log . e ( "---" , "Displaying Mouse." );
}
@ Override
public void visit ( Keyboard keyboard ) {
Log . e ( "---" , "Displaying Keyboard." );
}
@ Override
public void visit ( Monitor monitor ) {
Log . e ( "---" , "Displaying Monitor." );
}
}
5. ComputerPartDisplayVisitor를 사용하여 컴퓨터 구성 요소를 표시합니다.
ComputerPart computer = new Computer ();
computer . accept ( new ComputerPartDisplayVisitor ());
/*
*打印:
*---: Displaying Mouse.
*---: Displaying Keyboard.
*---: Displaying Monitor.
*---: Displaying Computer.
*/