代码之家  ›  专栏  ›  技术社区  ›  MOHSIN

遗传和构图混乱?

  •  1
  • MOHSIN  · 技术社区  · 9 年前

    我有一个抽象类 Area ,其子类为 Province , Division , District City .

    现在,我需要在 城市 类别,其中 district city 存在。所以,我将有一个 地区 类内部 城市 课(作文),这样我可以通过 id 特定的 地区 城市 并将其存储在数据库城市表中。但是,它不符合作文规则。因为区有市,而不是相反。

    另一个问题是,这两个类都是使用继承和组合的,我觉得这是不对的。

    一周来,我一直试图通过谷歌和其他东西独自解决这个问题。但是,我无法解决这个问题。我想这是我最后的希望。 我该如何解决这个问题?有什么例子吗?

    2 回复  |  直到 9 年前
        1
  •  1
  •   Makoto    9 年前

    我只看到这里的抽象。你有一个 Area ,可能是 Province , Division , District City ,但就继承而言,这是关系的最大限度。当然,这确实提出了一个问题,“除了一个足以创建继承层次结构的名称,而不是一个接口之外,一个省、区、区或市之间还有什么共同点?”

    请记住,继承(在一定程度上,接口)始终定义为 是a 关系也就是说,就您的系统而言 地区 是一个 地区 ,和 城市 是一个 地区 。这两种说法在纸面上听起来都很好,而且这种说法并没有什么真正的错误。事实上,你可以把它移到一个界面上,结果可能会很好。

    你想保留的内容 分离 从这个角度来看 具有a 关系,这就是作文所介绍的。

    这种关系可能是双向的,但主要前提是:

    • A. 城市 具有a 地区 .
    • A. 城市 具有a 分开 .
    • A. 城市 具有a 省份 .

    ……上述三个也具有相同的对应关系 城市 .

    这两种技术都可以使用,但你必须清楚:

    • 为什么? 你正在使用它们,并且
    • 什么时候 使用它们是最合适的。

    在这种情况下,它确实让人觉得继承是最不合理的,因为 getName() 方法可以 容易地 由四者之间的公共接口描述,并且不需要引入继承。

        2
  •  0
  •   callOfCode    9 年前

    非常有趣的问题,但缺少一个重要的细节- 上下文 什么将创造城市,什么将进入城市?哪些城市、地区等将负责?它们只是数据实体吗?我必须先回答这些问题,然后才能帮助你。因此,让我们开始设计我们的域模型:

    客户(顺其自然 main 方法)将通过 CountryBuilder 界面客户将通过 Registry 界面位置将是不可变的(客户端不允许直接修改位置数据)。允许客户端更改现有位置的唯一方法是通过 CountryBuilder公司 .所有位置 并且(按你的要求)知道(有名字)它是封闭的地方。 State 没有封闭的地方,但可以拥有 Districts . District 名称为 状态 并包含 Cities ,城市不能包含任何地方,但有其所有者的姓名 (ZipAddress) 当然,只使用一个抽象就可以达到同样的效果 Place ,但随后您需要使用一些检查来确定这个地方是什么,因为不是所有的地方都可以包含其他地方(例如城市),也不是所有地方都被其他地方包含(例如州),并且一些地方可以包含其他地方,也可以包含某些地方(地区)。为了避免检查,为了知道那个地方是市、区还是州,我使用了三种不同的抽象。您可以创建 状态 ,而不创建 City 也没有 地区 ,但您无法创建 城市 没有指定 状态 地区 。请阅读代码 小心 并阅读我在下面的评论:

    CountryClient.java 这是一个客户端类。它只能访问Country类的两个工厂方法。

    package com.ooDesign;
    
    import com.ooDesign.Country.Country;
    import com.ooDesign.Country.Country.City;
    import com.ooDesign.Country.Country.District;
    import com.ooDesign.Country.Country.State;
    import com.ooDesign.Country.Registry.NoSuchPlaceException;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    public class CountryClient 
    {
        public static void main(String[] args)
        {
            /*Creating various combinations of places.*/      
            build("ImaginaryState" , "ImaginaryDistrict", "MadCity");
            build("ImaginaryState" , "ImaginaryDistrict", "EastCity");
            build("ImaginaryState" , "ImaginaryDistrict", "WestCity");
            build("DamnGoodState" , "DamnGoodDistrict", "DamnGoodCity");
            build("ImaginaryState" , "ProgrammersDistrict", "NoLifersCity");
            build("DamnGoodState" , "DamnGoodDistrict", "DamnBadCity");
            /*"DamnGoodCity" in "DamnBadDistrict" is not the same as "DamnGoodCity" in "DamnGoodDistrict"
               since they are located in different districts. You can easily find out how to change implementation
               to not allow to build multiple cities with same name even if they are in different districts.*/
            build("DamnGoodState" , "DamnBadDistrict", "DamnGoodCity");
    
            /*Printing what we just created*/
            try
            {
                traverseWorld();
            } catch (NoSuchPlaceException ex)
            {
                Logger.getLogger(CountryClient.class.getName()).log(Level.SEVERE, null, ex);
            }
    
            /*Getting state of speciffic city (thanks to ZipCode interface)*/
            try
            {
                print(Country.registry().state("DamnGoodState").district("DamnBadDistrict").city("DamnGoodCity").zipCode().state());
            } catch (NoSuchPlaceException ex)
            {
                Logger.getLogger(CountryClient.class.getName()).log(Level.SEVERE, null, ex);
            }
    
        }
    
        static void print(String string)
        {
            System.out.println(string);
        }
    
        static void traverseWorld() throws NoSuchPlaceException
        {
            for(State s : Country.registry())
            {
                print("Districts in state \"" + s.name() + "\" :");
                for(District d : s)
                {
                    print("   Cities in district \"" + d.name() + "\" :");
                    for(City c : d)
                    {
                        print("      " + c.name());
                    }
                }
                print("---------------------------------------------");
            }
        }
    
        static void build(String state, String district, String city)
        {
            Country.builder().build().state(state).district(district).city(city);
        }
    
        static void build(String state, String district)
        {
            Country.builder().build().state(state).district(district);
        }
    
        static void build(String state)
        {
            Country.builder().build().state(state);
        }
    }
    

    国家.java 数据实体接口(市、区、州)的持有者,访问器(注册表)和Mutator(CountryBuilder)抽象的静态工厂。

    package com.ooDesign.Country;
    
    import java.util.HashMap;
    import com.ooDesign.Country.Registry.NoSuchPlaceException;
    
    public final class Country
    {
        private static HashMap<String, State> states = new HashMap<>();
    
        public static CountryBuilder builder()
        {
            return new CountryBuilderImpl(states);
        }
    
        public static Registry registry()
        {
            return new RegistryImpl(states);
        }
    
        public interface Place
        {
            String name();
        }
    
        public interface State extends Place, Iterable<District>
        {
            public District district(String districtName) throws NoSuchPlaceException;
        }
    
        public interface District extends Place, Iterable<City>
        {
            public City city(String cityName) throws NoSuchPlaceException;
            public String inState();
        }
    
        public interface City extends Place
        {
            public ZipCode zipCode();
        }
    
        public interface ZipCode
        {
            String state();
            String district();
            String city();
        }
    }
    

    CountryBuilder.java 我喜欢这种组合对象的构建方式,因为它的可读性。然后可以像这样实例化对象 Builder.build().firstObject(irstparams).secondObject(secondParams)...etc

    package com.ooDesign.Country;
    
    public interface CountryBuilder
    {
        public StateBuilder build();
    
        public interface StateBuilder
        {
           public DistrictBuilder state(String stateName);
        }
    
        public interface DistrictBuilder
        {
            public CityBuilder district(String districtName);
        }
    
        public interface CityBuilder
        {
            public void city(String cityName);
        }
    
    }
    

    CountryBuilderImpl.java CountryBuilder抽象的实现。

    package com.ooDesign.Country;
    
    import com.ooDesign.Country.Country.State;
    import static com.ooDesign.Country.Country.*;
    import com.ooDesign.Country.Registry.NoSuchPlaceException;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    class CountryBuilderImpl implements CountryBuilder
    {
        private Map<String, State> states;
    
        public CountryBuilderImpl(Map<String, State> states)
        {
            this.states = states;
        }
    
        @Override
        public StateBuilder build()
        {
            return new StateBuilder()
            {
                @Override
                public DistrictBuilder state(String stateName)
                {
    
                    StateImpl currentState;
                    if (states.containsKey(stateName))
                    {
                        currentState = (StateImpl)states.get(stateName);
                    } else
                    {
                        currentState = new StateImpl(stateName);
                        states.put(stateName, currentState);
                    }
    
                    return new DistrictBuilder()
                    {
                        @Override
                        public CityBuilder district(String districtName)
                        {
                            DistrictImpl currentDistrict = currentState.addDistrict(districtName);
    
                            return new CityBuilder()
                            {
                                @Override
                                public void city(String cityName)
                                {
                                    currentDistrict.addCity(cityName);
                                }
                            };
                        }
                    };
                }
            };
        }
    
        private static class StateImpl implements State
        {
    
            private final Map<String, District> districts;
            private final String stateName;
    
            StateImpl(String stateName)
            {
                this.districts = new HashMap<>();
                this.stateName = stateName;
            }
    
            DistrictImpl addDistrict(String districtName)
            {
                if (!districts.containsKey(districtName))
                {
                    districts.put(districtName, new DistrictImpl(stateName, districtName));
                }
                return (DistrictImpl)districts.get(districtName);
            }
    
            @Override
            public District district(String districtName) throws Registry.NoSuchPlaceException
            {
                if (!districts.containsKey(districtName))
                {
                    throw new Registry.NoSuchPlaceException("District \"" + districtName + "\" in state of " + stateName + " does not exists");
                } else
                {
                    return districts.get(districtName);
                }
            }
    
            @Override
            public String name()
            {
                return stateName;
            }
    
            @Override
            public Iterator<Country.District> iterator()
            {
                return districts.values().iterator();
            }
    
        }
    
        private static class DistrictImpl implements District
        {
    
            private final Map<String, Country.City> cities;
            private final String stateName, districtName;
    
            DistrictImpl(String stateName, String districtName)
            {
                this.cities = new HashMap<>();
                this.stateName = stateName;
                this.districtName = districtName;
            }
    
            void addCity(String cityName)
            {
                if (!cities.containsKey(cityName))
                {
                    cities.put(cityName, new CityImpl(new ZipImpl(stateName, districtName, cityName)));
                }
            }
    
            @Override
            public City city(String cityName) throws NoSuchPlaceException
            {
                if (!cities.containsKey(cityName))
                {
                    throw new Registry.NoSuchPlaceException("City \"" + cityName + "\" in state of " + stateName + " in district of " + districtName + " does not exists");
                } else
                {
                    return cities.get(cityName);
                }
            }
    
            CityImpl getCity(String cityName)
            {
                return (CityImpl)cities.get(cityName);
            }
    
            @Override
            public String inState()
            {
                return stateName;
            }
    
            @Override
            public String name()
            {
                return districtName;
            }
    
    
            @Override
            public Iterator<Country.City> iterator()
            {
                return cities.values().iterator();
            }
    
        }
    
        private static class CityImpl implements City
        {
    
            private final Country.ZipCode zipCode;
    
            public CityImpl(Country.ZipCode zipCode)
            {
                this.zipCode = zipCode;
            }
    
            @Override
            public Country.ZipCode zipCode()
            {
                return zipCode;
            }
    
            @Override
            public String name()
            {
                return zipCode.city();
            }
    
        }
    
        private static class ZipImpl implements ZipCode
        {
    
            private final String state, district, city;
    
            public ZipImpl(String state, String district, String city)
            {
                this.state = state;
                this.district = district;
                this.city = city;
            }
    
            @Override
            public String state()
            {
                return state;
            }
    
            @Override
            public String district()
            {
                return district;
            }
    
            @Override
            public String city()
            {
                return city;
            }
    
            public String toString()
            {
                return "ZIP_CODE: STATE - " + state + "; DISTRICT - " + district + "; CITY - " + city;
            }
        }
    }
    

    注册表.java 用于访问场所。

    package com.ooDesign.Country;
    
    import com.ooDesign.Country.Country.State;
    import java.util.Set;
    
    public interface Registry extends Iterable<State>
    {
        Set<String> listStates();
        State state(String stateName) throws NoSuchPlaceException;
    
        public static class NoSuchPlaceException extends Exception
        {
            public NoSuchPlaceException(String message)
            {
                super(message);
            }  
        }
    }
    

    注册实施.java 名字告诉我们它的目的。

    package com.ooDesign.Country;
    
    import com.ooDesign.Country.Country.State;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    
    class RegistryImpl implements Registry
    {
        private final Map<String, State> states;
    
        public RegistryImpl(Map<String, State> states)
        {
            this.states = states;
        }
    
        @Override
        public Set<String> listStates()
        {
            return states.keySet();
        }
    
        @Override
        public State state(String stateName) throws NoSuchPlaceException
        {
            if(!states.containsKey(stateName)) 
                throw new NoSuchPlaceException("State \"" + stateName + "does not exists");
            return states.get(stateName);
        }
    
        @Override
        public Iterator<State> iterator()
        {
            return states.values().iterator();
        }
    
    }
    

    正如您所看到的,实现与客户机是隔离的,因为它们位于单独的包中,并且实现类不是公共的。客户端只能通过接口与它们交互。接口有许多用途和优点。它们是面向对象设计的核心。我会留下来让你了解如何获得特定州的所有城市、特定州的全部地区、特定地区的所有城市等。这很容易做到。如果你愿意,你可以实现许多方便的方法,各种管理类 必须 如果您正在编写高质量、可维护的软件)。所有这些代码都只是为了向您展示OO设计的大图。事实上,这真的很棒,因为你有足够的热情去寻找整个星期的答案。我的建议是,如果你开始学习一个新概念,就找一本好书读一读。面向对象的设计和软件架构非常庞大。而且很漂亮。但是,如果你想看到它的辉煌,你需要掌握它。阅读书籍 图案上的Holub ,它一定会帮助你。 附笔 请随时询问有关代码的问题,如果发现错误,请通知我。祝你好运