【问题标题】:Express mutual connection at initialization初始化时表达相互连接
【发布时间】:2021-01-27 09:59:10
【问题描述】:

在一个对象处理多个其他对象的情况下,如何在初始化时表示所有权?

例如,假设有一只鸡孵化多个鸡蛋。小鸡没有父母是不好的,但小鸡也应该只把注意力集中在它的小鸡身上。如果这种关系在初始化的时候就表达出来,怎么可能呢?

在这种情况下哪种设计模式最适合使用?

如果可能,最好避免使用null,因为这可能会给系统带来歧义。如果使用它是不可避免的,如何才能最好地减少歧义?

示例程序:

public class MyClass {

    /**
     * Handles eggs
     * */
    public static class Chicken{
        private Egg[] eggs;
        
        public Chicken(Egg... eggs_){
            eggs = eggs_;
        }
        
        public void accept_signal(String message){
            /* ... */
        }
    }
    
    /**
     * Signals when its ready to hatch
     * */
    public static abstract class Egg{
        private final Chicken parent;
        public Egg(Chicken parent_){
            parent = parent_;
        }
        
        public void hatch(){
            parent.accept_signal("chirp chirp");
        }
    }
    
    /**
     * The resulting children to be handled
     * */
    public static class YellowChick extends Egg{
        public YellowChick(Chicken parent_){
            super(parent_);
        }
    }
    
    public static class BrownChick extends Egg{
        public BrownChick(Chicken parent_){
            super(parent_);
        }
    }
    
    public static class UglyDuckling extends Egg{
        public UglyDuckling(Chicken parent_){
            super(parent_);
        }
    }

    public static void main (String[] args){
        Chicken momma = new Chicken(
        //  new YellowChick(), new BrownChick(), new UglyDuckling()  /* How can these objects be initialized properly? */
        );
    }

}

【问题讨论】:

  • 您可以添加一个方法Chicken#addEgg并在Egg构造函数中调用它。
  • 这里的问题是应该在初始化时设置鸡蛋的数量(它是一个数组),而且,没有没有鸡蛋列表的 Chicken 对象......那么哪个先出现? :D

标签: java design-patterns


【解决方案1】:

软件中的循环依赖通常是个坏主意。
像这样的问题的解决方案,

Chicken <--> Egg

...是引入一个管理关系的中间人。
管理器可以通过不同的方式实现。

  • Chicken --> PoultryMediator <-- Egg
    在这里,经理充当调解人,在运行时回答查询并提供参考。
  • Chicken <-- PoultryInjector --> Egg
    在这里,管理器充当依赖注入器,在构建时连接对象。

有关一些相关链接,另请参阅:Spot problems with circular dependency

【讨论】:

  • 你认为Builder模式可以用作依赖注入器吗?
  • 也许可以,但是 Builder 模式不必要地使问题复杂化,因为没有它 DI 会更简单。
  • 感谢您的回答! :) 我可以请你批评我给出的答案吗?
  • 我认为代码的复杂度超过了问题的复杂度,即过度设计;但这对于学术练习来说很好。请注意,如果您的代码完全可以运行并且可以运行,您可以将其发布到codereview.stackexchange.com
  • 感谢您的反馈! :) 它作为一个独立的例子工作。由于实际的问题比这更复杂,所以我没有花精力在上面,我只是想通过一个简单的例子来说明问题。
【解决方案2】:

The Builder Pattern可以作为一个依赖inector来消除初始化过程中的死锁。由于Chicken 类依赖于一个接口(@98​​7654325@),该接口本身无法实例化,因此可以应用this question 中提到的模式。

这个例子有3个版本的介绍。第一个更简单,但它也提供了访问半完成的Chicken 类的可能性。在每个版本中,都以复杂性为代价消除了越来越多的歧义。

public class MyClass {

    /**
     * Handles eggs
     * */
    public static class Chicken{
        private Egg[] eggs;

        private Chicken(){}
        private void setEggs(Egg... eggs_){ eggs = eggs_; }

        public void accept_signal(String message){ /* ... */ }

        public static class Builder{
            Chicken momma;
            public Builder(){
                momma = new Chicken();
            }

            public Chicken build(Egg... eggs){
                momma.setEggs(eggs);
                return momma;
            }

            public Chicken get(){
                return momma;
            }
        }
    }

    /**
     * Signals when its ready to hatch
     * */
    public static abstract class Egg{
        private final Chicken parent;
        public Egg(Chicken parent_){
            parent = parent_;
        }

        public void hatch(){
            parent.accept_signal("chirp chirp");
        }
    }

    /**
     * The resulting children to be handled
     * */
    public static class YellowChick extends Egg{
        public YellowChick(Chicken parent_){
            super(parent_);
        }
    }

    public static class BrownChick extends Egg{
        public BrownChick(Chicken parent_){
            super(parent_);
        }
    }

    public static class UglyDuckling extends Egg{
        public UglyDuckling(Chicken parent_){
            super(parent_);
        }
    }

    public static void main (String[] args){
        Chicken.Builder mommaBuilder = new Chicken.Builder();
        Chicken momma = mommaBuilder.build(
            new YellowChick(mommaBuilder.get()), 
            new BrownChick(mommaBuilder.get()), 
            new UglyDuckling(mommaBuilder.get())
        );
        System.out.println("Success!");
    }

}

另一个版本旨在使用来自this question 的解决方案将访问半完成的Chicken 类仅限于相关类(Egg 的子类):

import java.util.Objects;

public class MyClass {

    /**
     * Handles eggs
     * */
    public static class Chicken{
        private Egg[] eggs;

        private Chicken(){}
        private void setEggs(Egg... eggs_){ eggs = eggs_; }

        public void accept_signal(String message){
            /* ... */
        }

        public static class Builder{
            Chicken momma;
            public Builder(){
                momma = new Chicken();
            }

            public Chicken build(Egg... eggs){
                momma.setEggs(eggs);
                return momma;
            }

            public Chicken get(Egg.Token token){
                Objects.requireNonNull(token, "Only call this in function from a valid Builder");
                return momma;
            }
        }
    }

    /**
     * Signals when its ready to hatch
     * */
    public static abstract class Egg{
        public static class Token{ private Token(){}}
        private final Chicken parent;
        public Egg(Chicken.Builder builder){
            parent = builder.get(new Token());
        }

        public void hatch(){
            parent.accept_signal("chirp chirp");
        }
    }

    /**
     * The resulting children to be handled
     * */
    public static class YellowChick extends Egg{
        public YellowChick(Chicken.Builder builder){
            super(builder);
        }
    }

    public static class BrownChick extends Egg{
        public BrownChick(Chicken.Builder builder){
            super(builder);
        }
    }

    public static class UglyDuckling extends Egg{
        public UglyDuckling(Chicken.Builder builder){
            super(builder);
        }
    }

    public static void main (String[] args){
        Chicken.Builder mommaBuilder = new Chicken.Builder();
        Chicken momma = mommaBuilder.build(
            new YellowChick(mommaBuilder), 
            new BrownChick(mommaBuilder), 
            new UglyDuckling(mommaBuilder)
        );
        System.out.println("Success!");
    }

}

尽管这仍然允许使用不同的构建器实例构建每个小鸡,并且仍然添加到 Chicken 下。为了解决这个问题,只要 Chicken 有来自另一个巢穴的 Chick (Chicken.Builder),就会引发异常:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class MyClass {

    /**
     * Handles eggs
     * */
    public static class Chicken{
        private Egg[] eggs;

        private Chicken(){}
        private void setEggs(Egg... eggs_){ eggs = eggs_; }

        public void accept_signal(String message){
            /* ... */
        }

        public static class Builder{
            Chicken momma;
            HashSet<Integer> accessors;
            public Builder(){
                momma = new Chicken();
                accessors = new HashSet<>();
            }

            public Chicken build(Egg... eggs){
                for(Egg egg : eggs){
                    if(!accessors.contains(egg.getToken()))
                        throw new IllegalStateException("Unable to accept step-chick!");
                }
                momma.setEggs(eggs);
                return momma;
            }

            public Chicken get(Egg.Token token){
                Objects.requireNonNull(token, "Only call this in function from a valid Builder");
                accessors.add(token.hashCode());
                return momma;
            }
        }
    }

    /**
     * Signals when its ready to hatch
     * */
    public static abstract class Egg{
        public static class Token{ private Token(){}}
        private final Chicken parent;
        private final Token token = new Token();
        public Egg(Chicken.Builder builder){
            parent = builder.get(token);
        }
        public int getToken(){return token.hashCode();}
        public void hatch(){
            parent.accept_signal("chirp chirp");
        }
    }

    /**
     * The resulting children to be handled
     * */
    public static class YellowChick extends Egg{
        public YellowChick(Chicken.Builder builder){
            super(builder);
        }
    }

    public static class BrownChick extends Egg{
        public BrownChick(Chicken.Builder builder){
            super(builder);
        }
    }

    public static class UglyDuckling extends Egg{
        public UglyDuckling(Chicken.Builder builder){
            super(builder);
        }
    }

    public static void main (String[] args){
        Chicken.Builder mommaBuilder = new Chicken.Builder();
        Chicken momma = mommaBuilder.build(
            new YellowChick(mommaBuilder),
            new BrownChick(mommaBuilder),
            new UglyDuckling(mommaBuilder)
        );
        System.out.println("Success!");
    }

}

【讨论】:

    猜你喜欢
    • 2014-04-15
    • 1970-01-01
    • 2018-04-25
    • 1970-01-01
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多