Demonstração do modo composto

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

Publicado 138 artigos originais · elogiou 34 · 150.000 visualizações

Acho que você gosta

Origin blog.csdn.net/bbj12345678/article/details/105289839
Recomendado
Clasificación