Padrão de design (padrão de design) é um conjunto de resumos classificados e catalogados da experiência de design de código que é usado repetidamente e é conhecido pela maioria das pessoas.
Os padrões de design são divididos em três tipos, com um total de 23 tipos:
Escrito com referência a artigos em Hongyang, Tutoriais para iniciantes, etc. Por favor, corrija-me se houver algum erro. Se houver alguma violação, entre em contato comigo para excluí-lo.
1. Padrão de design Observer Pattern (Observer Pattern) Tomando o serviço público WeChat como exemplo
2. Design Pattern Factory Pattern (Factory Pattern) começa com a venda de Roujiamo
3. Análise completa do padrão de design Singleton (padrão Singleton)
4. Padrão de design Strategy Pattern (Strategy Pattern) tem jogos de RPG como pano de fundo
5. Padrão de design Padrão de adaptador (padrão de adaptador) Tome o carregador de celular como exemplo
6. Design Pattern Command Pattern para gerenciar eletrodomésticos inteligentes
7. Design Pattern Decorator Pattern leva você de volta ao mundo lendário
8. Modo de design, modo de aparência (padrão de fachada) modo de filme com um clique
9. Design Pattern Template Method Pattern mostra o dia de um programador
10. Design Pattern State Pattern (State Pattern) Tome uma máquina de venda automática como exemplo
11. Design Pattern Builder Pattern (Builder Pattern) Considere construir e comprar um carro como exemplo
12. Padrão de protótipo de padrão de design (padrão de protótipo) Tome como exemplo a obtenção de múltiplas formas
13. Padrão de design Flyweight Pattern (Flyweight Pattern) obtém aleatoriamente várias formas como exemplo
14. Design Pattern Proxy Pattern (Proxy Pattern) Tome como exemplo a obtenção de imagens do disco
15. Padrão de design Bridge Pattern (Padrão Bridge) Tome como exemplo o desenho de círculos de cores diferentes
16. Padrão de combinação de padrão de design (padrão composto) Tome como exemplo a criação e impressão da hierarquia de funcionários
17. Padrão de design Iterator Pattern (Iterator Pattern) Use um iterador para imprimir nomes como exemplo
18. Design Pattern Mediator Pattern (Mediator Pattern) Tomando salas de bate-papo públicas como exemplo
19. Design Pattern Memento Pattern (Memento Pattern) Use memento como exemplo
20. Padrão de intérprete de padrão de design (padrão de intérprete) Considere a explicação de uma frase como exemplo
21. Padrão de Design Padrão de Cadeia de Responsabilidade (Padrão de Cadeia de Responsabilidade) Tome como exemplo a impressão de logs no Android Studio
22. Padrão de design Visitor Pattern (Visitor Pattern) Considere a exibição dos componentes do computador como exemplo
- Observador
- Fábrica
- Solteiro
- Estratégia
- Adaptador
- Comando
- Decorador
- Fachada
- Método de modelo
- Estado
- Construtor
- Protótipo
- Peso mosca
- Procurador
- Ponte
- Composto
- Iterador
- Mediador
- Lembrança
- Cadeia de Responsabilidade
- Visitante
Define dependências um-para-muitos entre objetos, para que quando um objeto for alterado, todas as suas dependências sejam notificadas e atualizadas automaticamente.
Existem muitos lugares no JDK ou Andorid que implementam o padrão observador, como XXXView.addXXXListenter. É claro que XXXView.setOnXXXListener não é necessariamente o padrão observador, porque o padrão observador é um relacionamento um-para-muitos, e para setXXXListener, é um par. O relacionamento entre 1 e 1 deve ser chamado de retorno de chamada.
Interface especial: Subject.java;
/**
* 注册一个观察者
*/
public void registerObserver ( Observer observer );
/**
* 移除一个观察者
*/
public void removeObserver ( Observer observer );
/**
* 通知所有观察者
*/
public void notifyObservers ();
Classe de implementação da conta de serviço 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 ();
}
Todos os observadores precisam implementar esta interface: Observer.java
public ObserverUser1 ( Subject subject ) {
subject . registerObserver ( this );
}
@ Override
public void update ( String msg ) {
Log . e ( "-----ObserverUser1 " , "得到 3D 号码:" + msg + ", 我要记下来。" );
}
Teste final: ObserverActivity.java
// 创建服务号
objectFor3D = new ObjectFor3D ();
// 创建两个订阅者
observerUser1 = new ObserverUser1 ( objectFor3D );
observerUser2 = new ObserverUser2 ( objectFor3D );
// 两个观察者,发送两条信息
objectFor3D . setMsg ( "201610121 的3D号为:127" );
objectFor3D . setMsg ( "20161022 的3D号为:000" );
Vamos listar brevemente a família desse padrão:
1. Modo de fábrica estático
2. Modo de fábrica simples (comprando Roujiamo na loja)
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. Modelo de método de fábrica (abertura de filial)
Fornece métodos abstratos para criar Roujia MoStore: RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo ( String type );
Implementação específica do método abstrato: XianRoujiaMoStore.java
A filial ainda usa o modelo de fábrica simples: XianSimpleRoujiaMoFactory.java
4. Padrão abstrato de fábrica (usando matérias-primas oficiais)
/**
* 准备工作
*/
public void prepare ( RoujiaMoYLFactory roujiaMoYLFactory ) {
Meet meet = roujiaMoYLFactory . creatMeet ();
YuanLiao yuanLiao = roujiaMoYLFactory . creatYuanLiao ();
Log . e ( "---RoujiaMo:" , "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:" + meet + "yuanLiao:" + yuanLiao );
}
O modo singleton serve principalmente para evitar o desperdício de recursos causado pela criação de múltiplas instâncias, e múltiplas instâncias podem facilmente levar a resultados incorretos devido a múltiplas chamadas. O uso do modo singleton pode garantir que haja apenas uma instância em todo o aplicativo .
Definição: Apenas três etapas são necessárias para garantir a exclusividade de um objeto
Comparar definição:
Estilo Hungry Han [disponível]: SingletonEHan.java
Contém estilo Han preguiçoso [recomendado bloqueio de verificação dupla]: 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 ;
}
Padrão de estratégia: define uma família de algoritmos e os encapsula separadamente para torná-los intercambiáveis. Esse padrão permite que as alterações no algoritmo sejam independentes dos clientes que os utilizam.
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 (); // 防御
Definição: Converte a interface de uma classe em outra interface esperada pelo cliente. O adaptador permite que classes com interfaces incompatíveis cooperem entre si. Esta definição está correta, dizendo que a função de um adaptador é converter uma interface em outra interface.
Tomemos o carregador como exemplo: os carregadores de celular geralmente têm cerca de 5 V. Nossa voltagem CA doméstica na China é de 220 V, portanto, o carregamento do celular requer um adaptador (redutor de voltagem).
Um telefone celular: Mobile.java
O telefone depende de uma interface que fornece tensão de 5 V: V5Power.java
O que temos é CA doméstico de 220 V: V220Power.java
Adaptador para completar a função de conversão de 220V em 5V : V5PowerAdapter.java
Teste final: Carregue o telefone:
Mobile mobile = new Mobile ();
V5Power v5Power = new V5PowerAdapter ( new V200Power ());
mobile . inputPower ( v5Power );
Definição: encapsular "solicitações" em objetos para que outros objetos possam ser parametrizados usando diferentes solicitações, filas ou logs. O modo de comando também suporta operações que podem ser revertidas. (Simplificação: encapsular a solicitação em um objeto e separar o solicitante da ação e o executor da ação.)
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 );
Padrão Decorator: Para ampliar a funcionalidade, os decoradores fornecem uma alternativa mais flexível à integração, atribuindo dinamicamente responsabilidades aos objetos.
Vamos descrever brevemente onde o padrão decorador entra em ação. Quando projetamos uma classe, precisamos adicionar algumas funções auxiliares a essa classe e não queremos alterar o código dessa classe. jogar. Está na hora. Isto também reflete um princípio: as aulas devem ser abertas a extensões e fechadas a modificações.
Requisitos: Projetar o sistema de equipamentos do jogo O requisito básico é ser capaz de calcular o poder de ataque e a descrição de cada equipamento após ser incorporado com diversas joias:
1. Superclasse de equipamento: IEquip.java
2. Classes de implementação de cada equipamento:
3. Superclasse de decorações (as decorações também pertencem aos equipamentos): IEquipDecorator.java
4. Classe de implementação de decorações:
5. Teste final: Calcule o poder de ataque e veja a descrição:
Log . e ( "---" , "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: " );
IEquip iEquip = new RedGemDecorator ( new RedGemDecorator ( new BlueGemDecorator ( new ShoeEquip ())));
Log . e ( "---" , "攻击力:" + iEquip . caculateAttack ());
Log . e ( "---" , "描述语:" + iEquip . description ());
Definição: Fornece uma interface unificada para acessar um grupo de interfaces no subsistema. A aparência define uma interface de alto nível para tornar o subsistema mais fácil de usar. Na verdade, para conveniência dos clientes, um grupo de operações é encapsulado em um método.
Demanda: Prefiro assistir filmes, então comprei projetor, computador, aparelho de som, projetei a iluminação da sala e comprei uma máquina de pipoca. Aí, quando quiser assistir a um filme, preciso assistir com um clique e desligar com um clique. .
Switch e outras operações para cada classe de dispositivo:
por exemplo: Máquina de pipoca: PopcornPopper.java
Aula de cinema: HomeTheaterFacade.java
/**
* 一键观影
*/
public void watchMovie () {
computer . on ();
light . down ();
popcornPopper . on ();
popcornPopper . makePopcorn ();
projector . on ();
projector . open ();
player . on ();
player . make3DListener ();
}
Teste final: visualização de filme com um clique:
new HomeTheaterFacade ( computer , light , player , popcornPopper , projector ). watchMovie ();
Definição: Define o esqueleto de um algoritmo e adia algumas etapas para subclasses. O método modelo permite que as subclasses redefinam as etapas do algoritmo sem alterar a estrutura do algoritmo.
Requisitos: Descreva resumidamente: Nossa empresa possui programadores, testadores, RH, gerentes de projeto, etc. O modo de método de modelo é usado abaixo para registrar o status de trabalho de todo o pessoal.
Três tipos de funções no padrão de método de modelo
1. Método Concreto
2. Método Abstrato
3. Método do Gancho
Superclasse de trabalho: 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 + "---离开公司" );
}
Classe de implementação do programador (o tempo pode ser conhecido): ITWorker.java
/**
* 重写父类的此方法,使可以查看离开公司时间
*/
@ Override
public boolean isNeedPrintDate () {
return true ;
}
Teste final:
Veja como todos estão trabalhando:
QAWorker qaWorker = new QAWorker ( "测试人员" );
qaWorker ();
HRWorker hrWorker = new HRWorker ( "莉莉姐" );
hrWorker . workOneDay ();
...
Verifique quando o programador saiu da empresa:
ITWorker itWorker = new ITWorker ( "jingbin" );
itWorker . workOneDay ();
Definição: Permite que um objeto mude seu comportamento quando seu estado interno muda, fazendo com que o objeto pareça ter modificado sua classe.
A definição está se tornando vaga novamente. Pense nisso quando o estado interno de um objeto muda, seu comportamento muda com a mudança de estado.
Requisitos: tome uma máquina de venda automática como exemplo (existem status como moeda inserida e não inserida e métodos de inserção e devolução de moedas)
Implementação inicial da máquina de venda automática a ser melhorada: VendingMachine.java
Máquina de venda automática aprimorada (mais maleável): 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 ;
}
Interface de estado: State.java
Classe de implementação de interface correspondente ao estado:
Teste de máquina de venda automática aprimorado:
// 初始化售货机,且里面有3个商品
VendingMachineBetter machineBetter = new VendingMachineBetter ( 3 );
machineBetter . insertMoney ();
machineBetter . turnCrank ();
O modo de construção é o modo de criação de objetos. O modo de construção pode separar a representação interna de um produto do processo de produção do produto, de modo que um processo de construção pode gerar objetos de produto com diferentes representações internas.
Requisitos: Os usuários vão a uma loja de automóveis para comprar um carro.
Análise: A oficina extrai os carros correspondentes de acordo com a necessidade de cada usuário
Superclasse do construtor: Construtor
public abstract class Builder {
public abstract void setPart ( String name , String type );
public abstract Product getProduct ();
}
Classe de implementação correspondente do construtor: 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 ;
}
}
O gerente da loja pega o carro:
// 店长
Director director = new Director ();
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
Product product = director . getBProduct ();
// 展示汽车信息
product . showProduct ();
O padrão de protótipo é usado para criar objetos repetidos enquanto garante desempenho. Este tipo de padrão de design é um padrão de criação, que fornece uma maneira ideal de criar objetos.
Este padrão implementa uma interface de protótipo que é usada para criar um clone do objeto atual. Este modo é usado quando o custo de criação direta de objetos é relativamente alto. Por exemplo, um objeto precisa ser criado após uma operação cara de banco de dados. Podemos armazenar o objeto em cache, retornar um clone dele na próxima solicitação e atualizar o banco de dados quando necessário para reduzir as chamadas ao banco de dados.
Tomando como exemplo a obtenção de múltiplas formas, existem quatro etapas:
1. Crie uma classe abstrata que implemente a interface Cloneable. Forma (implementa Clonável)
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. Crie uma classe de entidade que estenda a classe abstrata acima. Círculo, Retângulo, Quadrado
public class Circle extends Shape {
public Circle () {
type = "Circle" ;
}
@ Override
public void draw () {
Log . e ( "---" , "Inside Circle::draw() method." );
}
}
3. Crie uma classe para obter classes de entidade do banco de dados e armazená-las em uma Hashtable. ShapeCache
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. Use a classe ShapeCache para obter um clone da forma armazenada no Hashtable.
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache . loadCache ();
Shape shapeCache1 = ShapeCache . getShape ( "1" );
Shape shapeCache2 = ShapeCache . getShape ( "2" );
Shape shapeCache3 = ShapeCache . getShape ( "3" );
Usado principalmente para reduzir o número de objetos criados para reduzir o uso de memória e melhorar o desempenho. Este tipo de padrão de projeto é um padrão estrutural, que fornece uma maneira de reduzir o número de objetos e, assim, melhorar a estrutura do objeto exigida pela aplicação.
O padrão Flyweight tenta reutilizar objetos existentes do mesmo tipo ou criar novos objetos se nenhum objeto correspondente for encontrado. Demonstraremos esse padrão criando 5 objetos que desenham 20 círculos em locais diferentes. Como existem apenas 5 cores disponíveis, a propriedade color é usada para verificar o objeto Círculo existente.
Tomando como exemplo a obtenção aleatória de múltiplas formas, existem quatro etapas:
1. Crie uma interface.
public interface Shape {
void draw ();
}
2. Crie uma classe de entidade que implemente a interface.
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. Crie uma fábrica para gerar objetos de classes de entidades com base nas informações fornecidas.
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. Use esta fábrica para obter o objeto da classe de entidade passando informações de cor.
for ( int i = 0 ; i < 20 ; i ++) {
Circle circle = ( Circle ) ShapeFactory . getShape ( getRandomColor ());
circle . setX ( getRandomX ());
circle . setY ( getRandomY ());
circle . setRadius ( 100 );
circle . draw ();
}
Uma classe representa a funcionalidade de outra classe. No padrão proxy, criamos objetos com objetos existentes para fornecer uma interface funcional para o mundo exterior. Pode-se entender que se não existir tal objeto na memória, ele será criado, e se houver, o objeto será retornado diretamente.
Tomando como exemplo a obtenção de fotos do disco, há três etapas no total:
1. Crie uma interface.
public interface Image {
void display ();
}
2. Crie uma classe de entidade RealImage que implemente a interface. Classe de proxy correspondente: 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. Quando solicitado, utilize ProxyImage para obter um objeto da classe RealImage.
Image image = new ProxyImage ( "test_10mb.png" );
// 第一次是new的,图像从磁盘加载
image . display ();
// 第二次取缓存,图像不需要从磁盘加载
image . display ();
Bridge é usado para dissociar abstração e implementação para que as duas possam mudar independentemente. Este tipo de padrão de design é um padrão estrutural, que separa abstração e implementação, fornecendo uma estrutura de ponte entre elas.
Tomando como exemplo o desenho de círculos de cores diferentes, a implementação é dividida em cinco etapas:
1. Crie uma interface de implementação de ponte.
public interface DrawAPI {
void drawCircle ( int radius , int x , int y );
}
2. Crie uma classe de implementação de ponte de entidade que implemente a interface DrawAPI. Círculo Vermelho, Círculo Verde
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. Use a interface DrawAPI para criar a classe abstrata Shape.
public abstract class Shape {
protected DrawAPI drawAPI ;
protected Shape ( DrawAPI drawAPI ) {
this . drawAPI = drawAPI ;
}
public abstract void draw ();
}
4. Crie uma classe de entidade que implemente a interface 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. Use as classes Shape e DrawAPI para desenhar círculos de cores diferentes.
// 画红圆
Circle circle = new Circle ( 10 , 10 , 100 , new RedCircle ()); s
circle . draw ();
// 画绿圆
Circle circle2 = new Circle ( 20 , 20 , 100 , new GreenCircle ());
circle2 . draw ();
Também chamado de padrão parte-todo, é usado para tratar um grupo de objetos semelhantes como um único objeto. O modo de composição combina objetos de acordo com uma estrutura em árvore, que é usada para representar hierarquias de partes e de todo. Este tipo de padrão de design é um padrão estrutural, que cria uma estrutura em árvore de grupos de objetos.
Tomemos como exemplo a criação e impressão de uma hierarquia de funcionários, o exemplo da menor unidade:
1. Crie uma classe Employee com uma lista de objetos 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. Utilize a classe Employee para criar e imprimir a hierarquia de funcionários.
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=[]}]}]}
*/
Padrão de design muito comum em ambientes de programação Java e .Net. Este padrão é usado para acessar os elementos de um objeto de coleção sequencialmente sem conhecer a representação subjacente do objeto de coleção. O padrão do iterador é um padrão comportamental.
Tomando como exemplo o uso de um iterador para imprimir nomes, há três etapas no total:
1. Crie uma interface:
public interface Iterator {
public boolean hasNext ();
public Object next ();
}
public interface Container {
public Iterator getIterator ();
}
2. Crie uma classe de entidade que implemente a interface Container. Esta classe possui uma classe interna NameIterator que implementa a interface Iterator.
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. Use NameRepository para obter o iterador e imprimir o nome.
NameRepository nameRepository = new NameRepository ();
for ( Iterator iterator = nameRepository . getIterator (); iterator . hasNext (); ) {
String name = ( String ) iterator . next ();
Log . e ( "---" , name );
/*
* /---: John
* /---: jingbin
* /---: youlookwhat
* /---: lookthis
*/
}
Usado para reduzir a complexidade da comunicação entre vários objetos e classes. Esse padrão fornece uma classe intermediária que normalmente lida com a comunicação entre diferentes classes e oferece suporte a acoplamento fraco, facilitando a manutenção do código. O modelo mediador é um modelo comportamental.
Tomando como exemplo uma sala de bate-papo pública, as etapas mínimas do exemplo da unidade são:
1. Crie uma classe intermediária.
public class CharRoom {
public static void showMessage ( User user , String message ) {
Log . e ( "---" , new Date (). toString ()
+ " [" + user . getName () + "] : " + message );
}
}
2. Crie a classe de usuário.
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. Utilize o objeto Usuário para exibir a comunicação entre eles.
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!
Salve um determinado estado de um objeto para que ele possa ser restaurado no momento apropriado. O modo memorando é um modo comportamental.
Tomando o memo como exemplo, as etapas unitárias mínimas são:
1. Crie a classe 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. Crie a classe Originador.
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. Crie a classe 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. Use objetos CareTaker e 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
*/
Fornece uma maneira de avaliar a sintaxe ou expressões de uma linguagem e é um padrão comportamental. Este padrão implementa uma interface de expressão que interpreta um contexto específico. Este modo é usado na análise SQL, mecanismos de processamento de símbolos, etc.
Considere a explicação de uma frase como exemplo, as etapas unitárias mínimas:
1. Crie uma interface de expressão Expressão.
public interface Expression {
public boolean interpreter ( String content );
}
2. Crie uma classe de entidade que implemente a interface acima. TerminalExpressão, OrExpressão, AndExpressão.
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. Use a classe Expressão para criar regras e analisá-las.
/**
* 规则: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" ));
O Padrão Cadeia de Responsabilidade cria uma cadeia de objetos destinatários para uma solicitação. Esse padrão desacopla o remetente e o destinatário da solicitação com base no tipo de solicitação. Este tipo de padrão de design é um padrão comportamental. Neste padrão, normalmente cada receptor contém uma referência a outro receptor. Se um objeto não puder lidar com a solicitação, ele passará a mesma solicitação para o próximo destinatário e assim por diante.
Tomando como exemplo a impressão de logs no Android Studio, as etapas mínimas da unidade são:
1. Crie uma classe de criador de logs abstrata 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. Crie uma classe de entidade que estenda a classe do criador de logs.
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. Crie diferentes tipos de registradores. Dê a eles diferentes níveis de erro e dentro de cada registrador defina o próximo registrador. O próximo criador de logs em cada criador de logs representa parte da cadeia.
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." );
No padrão visitante, usamos uma classe visitante, que altera o algoritmo de execução da classe do elemento. Desta forma, o algoritmo de execução do elemento pode mudar conforme o visitante muda. Este tipo de padrão de design é um padrão comportamental. De acordo com o esquema, o objeto elemento aceitou um objeto visitante para que o objeto visitante possa manipular operações no objeto elemento.
Tomando como exemplo os componentes de um computador com tela, ele é implementado principalmente em cinco etapas:
1. Defina uma interface que represente o elemento.
public interface ComputerPart {
public void accept ( ComputerPartVisitor computerPartVisitor );
}
2. Crie uma classe de entidade que estenda a classe acima. Teclado, monitor, mouse, computador
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. Defina uma interface que represente os visitantes.
public interface ComputerPartVisitor {
public void visit ( Computer computer );
public void visit ( Mouse mouse );
public void visit ( Keyboard keyboard );
public void visit ( Monitor monitor );
}
4. Crie uma entidade visitante que implemente a classe acima.
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. Use ComputerPartDisplayVisitor para exibir os componentes do computador.
ComputerPart computer = new Computer ();
computer . accept ( new ComputerPartDisplayVisitor ());
/*
*打印:
*---: Displaying Mouse.
*---: Displaying Keyboard.
*---: Displaying Monitor.
*---: Displaying Computer.
*/