O modo composto é combinar os modos aprendidos anteriormente para resolver problemas juntos. O modo composto geralmente combina dois ou mais modos em uma solução para resolver o problema .
Abaixo, usamos um exemplo para ilustrar a aplicação do modo composto
1. Queremos deixar um grupo de patos latir, porque latir é o comportamento de patos e o chamado de patos diferentes é diferente, por isso criamos uma interface pública Quackable
package duck;
/**
* 鸭子将实现这个接口,然后实现各自不同的叫声
*/
public interface Quackable
{
public void quack();
}
2. Alguns patos implementam a interface Quackable
package duck;
/**
* 绿头鸭
*/
public class MallardDuck implements Quackable {
@Override
public void quack() {
System.out.println("呱呱呱");
}
}
package duck;
/**
* 红头鸭
*/
public class RedheadDuck implements Quackable {
@Override
public void quack() {
System.out.println("呱呱呱");
}
}
package duck;
/**
* 橡皮鸭
*/
public class RubberDuck implements Quackable {
@Override
public void quack() {
System.out.println("吱吱吱");
}
}
3. O simulador simula chamadas de patos
import duck.MallardDuck;
import duck.Quackable;
import duck.RedheadDuck;
import duck.RubberDuck;
import goose.Goose;
import goose.GooseAdapter;
public class Test
{
public static void main(String[] args) {
Test test = new Test();
test.go();
}
void go()
{
Quackable mallardDuck = new MallardDuck();
Quackable redheadDuck = new RedheadDuck();
Quackable rubberDuck = new RubberDuck();
simulate(mallardDuck);
simulate(redheadDuck);
simulate(rubberDuck);
}
void simulate(Quackable quackable)
{
quackable.quack();
}
}
呱呱呱
呱呱呱
吱吱吱
Até agora tudo bem. O exemplo acima é um exemplo muito simples, mas nenhum padrão é usado. Abaixo adicionaremos gradualmente algumas funções
Queremos adicionar alguns outros animais, onde houver patos, haverá gansos, então adicionamos um ganso, gansos, cacarejo
package goose;
/**
* 鹅类
*/
public class Goose
{
public void honk()
{
System.out.println("咯咯咯");
}
}
Adicionamos uma classe de ganso, ele não é do tipo pato, portanto não é do tipo Quackable, nem pode ser passado para a simulação (Quackable Quackable),
Queremos transformar o ganso em um tipo de pato, para que possamos usar o modo adaptador para adaptá-lo a um pato
package goose;
import duck.Quackable;
/**
* 利用适配器,我们可以将鹅适配成鸭子
*/
public class GooseAdapter implements Quackable {
Goose goose;
/**
* 构造器传入需要适配的对象
* @param goose
*/
public GooseAdapter(Goose goose) {
this.goose = goose;
}
/**
* 当调用quack方法时,会被委托到鹅的honk方法
*/
@Override
public void quack() {
goose.honk();
}
}
Agora que nosso simulador pode usar o ganso, criamos o objeto ganso e o envolvemos no adaptador para implementar a interface Quackable, para que possamos continuar
import duck.MallardDuck;
import duck.Quackable;
import duck.RedheadDuck;
import duck.RubberDuck;
import goose.Goose;
import goose.GooseAdapter;
public class Test
{
public static void main(String[] args) {
Test test = new Test();
test.go();
}
void go()
{
Quackable mallardDuck = new MallardDuck();
Quackable redheadDuck = new RedheadDuck();
Quackable rubberDuck = new RubberDuck();
//将鹅包装进适配器,就可以让鹅像鸭子一样,拥有鸭子的行为
Quackable goose = new GooseAdapter(new Goose());
simulate(mallardDuck);
simulate(redheadDuck);
simulate(rubberDuck);
//因为适配器是包装了鹅,并且实现了Quackable接口,所以能传入
simulate(goose);
}
void simulate(Quackable quackable)
{
quackable.quack();
}
}
simulate chamará o método quack () de muitos objetos, incluindo o método quack () do adaptador
呱呱呱
呱呱呱
吱吱吱
咯咯咯
Abaixo, teremos um novo requisito para contar o número de chamadas de pato. Como isso pode ser feito? Podemos criar um decorador e envolver o pato no objeto decorador para dar um novo comportamento ao pato (comportamento da contagem de cálculos) A vantagem disso é que não há necessidade de modificar o código dentro do pato. Este é o padrão do decorador
Em seguida, começamos a criar um decorador
package decorator;
import duck.Quackable;
/**
* 统计鸭子叫声的装饰者
* 和适配器一样它要实现目标接口
*/
public class QuackCounter implements Quackable
{
Quackable duck; //被装饰的对象
static int count; //我们用静态变量来跟踪所有呱呱叫次数
//将被装饰的对象传入构造器中,并记录在实例变量中
public QuackCounter(Quackable duck) {
this.duck = duck;
}
/**
* 当quack()被调用时,叫声次数加一
*/
@Override
public void quack() {
duck.quack();
count++;
}
/**
* 返回所有在Quackable中发生的呱呱叫次数
* @return
*/
public static int getCount()
{
return count;
}
}
Emulador
import decorator.QuackCounter;
import duck.MallardDuck;
import duck.Quackable;
import duck.RedheadDuck;
import duck.RubberDuck;
import goose.Goose;
import goose.GooseAdapter;
public class Test
{
public static void main(String[] args) {
Test test = new Test();
test.go();
}
void go()
{
//每创建一个Quackable,就用一个新的装饰者包装它,我们只统计鸭子的叫声,所以不用装饰鹅
Quackable mallardDuck = new QuackCounter(new MallardDuck());
Quackable redheadDuck = new QuackCounter(new RedheadDuck());
Quackable rubberDuck = new QuackCounter(new RubberDuck());
//将鹅包装进适配器,就可以让鹅像鸭子一样,拥有鸭子的行为
Quackable goose = new GooseAdapter(new Goose());
simulate(mallardDuck);
simulate(redheadDuck);
simulate(rubberDuck);
//因为适配器是包装了鹅,并且实现了Quackable接口,所以能传入
simulate(goose);
//我们查看鸭子呱呱叫了几次
System.out.println("鸭子总共叫了" + QuackCounter.getCount()+"次");
}
/**
* 这里没有任何变动,被装饰和被适配的对象,还是Quackable类
* @param quackable
*/
void simulate(Quackable quackable)
{
quackable.quack();
}
}
呱呱呱
呱呱呱
吱吱吱
咯咯咯
鸭子总共叫了3次
Esse contador de chamadas de patos é ótimo, mas descobrimos que muitos patos não são contados, porque esses patos não são embalados, por isso não têm efeito de contagem, esse é o problema do modo de decoração! E toda vez que você cria um objeto, você deve decorar um lado, caso se esqueça de decorar Não há efeito estatístico. Portanto, planejamos encapsular as peças criadas e decoradas, o que requer o padrão de fábrica
Então, em seguida, precisamos criar uma fábrica, que é especificamente responsável pela criação de patos decorados.Como essa fábrica precisa criar diferentes tipos de famílias de produtos de pato, precisamos usar o padrão abstrato de fábrica
Primeiro crie uma fábrica abstrata
package factory;
import duck.Quackable;
/**
* 我们定义一个抽象工厂,他们的子类会创建不同的家族
*/
public abstract class AbstractDuckFactory
{
public abstract Quackable createMallardDuck();
public abstract Quackable createRedheadDuck();
public abstract Quackable createRubberDuck();
}
Crie as fábricas que realmente precisamos, elas são responsáveis por criar o pato decorado
package factory;
import decorator.QuackCounter;
import duck.MallardDuck;
import duck.Quackable;
import duck.RedheadDuck;
import duck.RubberDuck;
/**
* CountingDuckFactory扩展自抽象工厂,创建被装饰过的鸭子,它们具有统计的行为
*/
public class CountingDuckFactory extends AbstractDuckFactory {
@Override
public Quackable createMallardDuck() {
return new QuackCounter(new MallardDuck());
}
@Override
public Quackable createRedheadDuck() {
return new QuackCounter(new RedheadDuck());
}
@Override
public Quackable createRubberDuck() {
return new QuackCounter(new RubberDuck());
}
}
Vamos modificar o simulador novamente
import decorator.QuackCounter;
import duck.MallardDuck;
import duck.Quackable;
import duck.RedheadDuck;
import duck.RubberDuck;
import factory.AbstractDuckFactory;
import factory.CountingDuckFactory;
import goose.Goose;
import goose.GooseAdapter;
public class Test
{
public static void main(String[] args) {
Test test = new Test();
AbstractDuckFactory countingDuckFactory = new CountingDuckFactory();
test.go(countingDuckFactory);
}
void go(AbstractDuckFactory countingDuckFactory)
{
//每创建一个Quackable,就用一个新的装饰者包装它,我们只统计鸭子的叫声,所以不用装饰鹅
// Quackable mallardDuck = new QuackCounter(new MallardDuck());
// Quackable redheadDuck = new QuackCounter(new RedheadDuck());
// Quackable rubberDuck = new QuackCounter(new RubberDuck());
//现在可以利用工厂来创建鸭子对象了
Quackable mallardDuck = countingDuckFactory.createMallardDuck();
Quackable redheadDuck = countingDuckFactory.createRedheadDuck();
Quackable rubberDuck = countingDuckFactory.createRubberDuck();
//将鹅包装进适配器,就可以让鹅像鸭子一样,拥有鸭子的行为
Quackable goose = new GooseAdapter(new Goose());
simulate(mallardDuck);
simulate(redheadDuck);
simulate(rubberDuck);
//因为适配器是包装了鹅,并且实现了Quackable接口,所以能传入
simulate(goose);
//我们查看鸭子呱呱叫了几次
System.out.println("鸭子总共叫了" + QuackCounter.getCount()+"次");
}
/**
* 这里没有任何变动,被装饰和被适配的对象,还是Quackable类
* @param quackable
*/
void simulate(Quackable quackable)
{
quackable.quack();
}
}
Como resultado da última corrida, desta vez podemos ter certeza de que todos os patos foram decorados, porque estamos usando o padrão de fábrica e não precisamos criar objetos sozinhos
呱呱呱
呱呱呱
吱吱吱
咯咯咯
鸭子总共叫了3次
Desta vez, o patrulheiro levantou outra questão: por que devemos gerenciar os patos individualmente? Se houver muitos patos, é uma bagunça
Portanto, precisamos pensar nesses patos como uma coleção e, da próxima vez que pedirmos, podemos deixar todos os patos agirem de acordo com as ordens deles, o que é muito conveniente.
Precisamos tratar as coleções como se fossem um único objeto, o que requer o uso de padrões de composição . Abaixo, criaremos uma classe composta que precisa implementar a mesma interface que o elemento do nó
package compose;
import duck.Quackable;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 创建鸭子组合类,操作这个组合就像和操作节点元素一样,所以它也和节点元素一样实现相同的接口
*/
public class Flock implements Quackable{
ArrayList quackers = new ArrayList();
/**
* 将节点元素记录到属于Flock的集合中
* @param quacker
*/
public void add(Quackable quacker)
{
quackers.add(quacker);
}
/**
* Flock也是Quackable,所以也具备quack()这个方法,此方法会对整个集合产生作用,
* 遍历ArrayList上的每一个元素上的quack()方法
*/
@Override
public void quack() {
Iterator<Quackable> iterator = quackers.iterator();
while (iterator.hasNext())
{
Quackable quacker = iterator.next();
quacker.quack();
}
}
}
Dessa vez, você não precisa passar os elementos do nó um por um, basta passar a combinação para o método simulate ()
import compose.Flock;
import decorator.QuackCounter;
import duck.MallardDuck;
import duck.Quackable;
import duck.RedheadDuck;
import duck.RubberDuck;
import factory.AbstractDuckFactory;
import factory.CountingDuckFactory;
import goose.Goose;
import goose.GooseAdapter;
public class Test
{
public static void main(String[] args) {
Test test = new Test();
AbstractDuckFactory countingDuckFactory = new CountingDuckFactory();
test.go(countingDuckFactory);
}
void go(AbstractDuckFactory countingDuckFactory)
{
//每创建一个Quackable,就用一个新的装饰者包装它,我们只统计鸭子的叫声,所以不用装饰鹅
// Quackable mallardDuck = new QuackCounter(new MallardDuck());
// Quackable redheadDuck = new QuackCounter(new RedheadDuck());
// Quackable rubberDuck = new QuackCounter(new RubberDuck());
//现在可以利用工厂来创建鸭子对象了
Quackable mallardDuck = countingDuckFactory.createMallardDuck();
Quackable redheadDuck = countingDuckFactory.createRedheadDuck();
Quackable rubberDuck = countingDuckFactory.createRubberDuck();
//将鹅包装进适配器,就可以让鹅像鸭子一样,拥有鸭子的行为
Quackable goose = new GooseAdapter(new Goose());
//创建组合元素Flock,然后把Quackable集合都放进去
Flock flock = new Flock();
flock.add(mallardDuck);
flock.add(redheadDuck);
flock.add(rubberDuck);
flock.add(goose);
//因为组合元素和节点元素都实现了共同接口,操作组合等同于操作节点元素
System.out.println("开始测试主群");
simulate(flock);
//我们查看鸭子呱呱叫了几次
System.out.println("鸭子总共叫了" + QuackCounter.getCount()+"次");
}
/**
* 这里没有任何变动,被装饰和被适配的对象,还是Quackable类
* @param quackable
*/
void simulate(Quackable quackable)
{
quackable.quack();
}
}
Concluído o mesmo efeito, na travessia do objeto combinado, também usamos o padrão de iterador
开始测试主群
呱呱呱
呱呱呱
吱吱吱
咯咯咯
鸭子总共叫了3次
Resumo: O que fizemos?
Um ganso apareceu, e ele queria ser como um Quackable, então usamos o modo de adaptador para combinar o ganso com o tipo Quackable. Agora você pode usar o método do adaptador quack () do ganso para fazer com que o ganso se solte
Então o estudioso de coaxar decidiu contar o número de coaxantes.A maioria de nós usou o modo decorador e adicionou um decorador chamado QuackCounting. É usado para rastrear o número de vezes que o quack () é chamado. E delegar a chamada para o objeto que ele decorou
Mas os quackers temem que tenham esquecido de adicionar o decorador Quackcounter. Portanto, usamos o padrão abstrato de fábrica para criar patos, colocá-los na necessidade de patos, basta perguntar à fábrica e a fábrica irá decorar os patos para eles.
É um pato e um ganso. Temos problemas de gerenciamento, por isso precisamos de um modelo de combinação para integrar muitos quackables em um grupo. Criamos um objeto composto. Ele também implementa a interface quackable do objeto de elemento, fazendo o usuário operá-lo como e Os elementos operacionais são os mesmos. Portanto, agora o cientista croak pode manipular diretamente uma coleção, ao iterá-la, use o padrão de iterador