C#OOP组成和概括同时进行

 一粒星尘ch 发布于 2023-01-07 09:29

这可能是一个简单/基本的OOP问题,但我仍然无法弄清楚如何解决它.我在访谈中遇到了以下问题:制作一个UML类图并编写一个"智能"手机的基本代码,其中包含电话和MP3播放器的功能.我们有以下(接受)解决方案:

class Telephone 
{
    public string name { get; set; }

    public Telephone()
    {
        name = "name telephone";
    }
}

class MP3 
{
    public string name { get; set; }

    public MP3()
    {
        name = "name mp3";
    }
}

而"智能"手机类:

class TelephoneMP3 
{
    public Telephone tel;
    public MP3 mp3;

    public TelephoneMP3()
    {
        tel = new Telephone();
        mp3 = new MP3();
    }
}

如您所见,我们在TelephoneMP3和Telephone/MP3类之间有一个组合关系.

但是,使用此代码,TelephoneMP3不是电话,而且TelephoneMP3也不是MP3,这是不合逻辑的.那么,为了使这个有效,我应该做些什么改变?例如,这种测试:

if (telMp3 is Telephone)
{
    Console.WriteLine("TelephoneMP3 is telephone");
}           
if (telMp3 is MP3)
{
    Console.WriteLine("TelephoneMP3 is mp3");
}

可以使用以下备注进行修改:

    电话/ MP3 /电话MP3必须保持上课(所有3个)

    如有必要,我可以添加接口/其他类

    (从一个接口继承时,例如在TelephoneMP3将不得不从该接口的所有成员编写的代码)TelephoneMP3不得复制所有从电话/ MP3的功能

先感谢您

5 个回答
  • 这里有一些很好的答案.说使用界面的答案是好的,这就是面试官可能正在寻找的.但是,我会考虑简单地否定这样一个前提,即"是一种"关系得到满足是一个好主意.相反,我会考虑使用服务提供商组织:

    public interface ITelephone { ... }
    internal class MyTelephone : ITelephone { ... }
    public interface IMusicPlayer { ... }
    internal class MyPlayer : IMusicPlayer { ... }
    public interface IServiceProvider
    {
      T QueryService<T>() where T : class;
    }
    
    internal class MyDevice : IServiceProvider
    {
      MyTelephone phone = new MyTelephone();
      MyPlayer player = new MyPlayer();
      public T QueryService<T>() where T : class
      {
          if (typeof(T) == typeof(ITelephone)) return (T)(object)phone;
          if (typeof(T) == typeof(IPlayer)) return (T)(object)player;
          return null;
      }
    }
    

    现在,呼叫者可以MyDevice通过其IServiceProvider界面进行操作.你问它

    ITelephone phone = myDevice.QueryService<ITelephone>();
    

    如果phone是非null,则设备可以像手机一样工作.但

    myDevice is ITelephone
    

    是假的.该设备不是手机,它知道如何找到像手机一样的东西.

    有关此内容的更多信息,请研究MAF等插件架构.

    2023-01-07 09:32 回答
  • 它几乎与其他答案类似,但是......
    我认为它在继承层次结构方面具有最佳准确性.

    internal class Program
    {
        private static void Main(string[] args)
        {
            var telephone = new Telephone();
            Console.WriteLine(telephone.Name);
            telephone.OutboundCall("+1 234 567");
            Console.WriteLine("Am I a Telephone?                 {0}", telephone is Telephone);
            Console.WriteLine("Am I a MP3?                       {0}", telephone is MediaPlayer3);
            Console.WriteLine("Am I a Smartphone?                {0}", telephone is Smartphone);
            Console.WriteLine("Do I Have Telephone Capabilities? {0}", telephone is ITelephone);
            Console.WriteLine("Do I Have MP3 Capabilities?       {0}", telephone is IMediaPlayer3);
            Console.WriteLine();
    
            var mp3 = new MediaPlayer3();
            Console.WriteLine(mp3.Name);
            mp3.PlaySong("Lalala");
            Console.WriteLine("Am I a Telephone?                 {0}", mp3 is Telephone);
            Console.WriteLine("Am I a MP3?                       {0}", mp3 is MediaPlayer3);
            Console.WriteLine("Am I a Smartphone?                {0}", mp3 is Smartphone);
            Console.WriteLine("Do I Have Telephone Capabilities? {0}", mp3 is ITelephone);
            Console.WriteLine("Do I Have MP3 Capabilities?       {0}", mp3 is IMediaPlayer3);
            Console.WriteLine();
    
            var smartphone = new Smartphone();
            Console.WriteLine(smartphone.Name);
            smartphone.OutboundCall("+1 234 567");
            smartphone.PlaySong("Lalala");
            Console.WriteLine("Am I a Telephone?                 {0}", smartphone is Telephone);
            Console.WriteLine("Am I a MP3?                       {0}", smartphone is MediaPlayer3);
            Console.WriteLine("Am I a Smartphone?                {0}", smartphone is Smartphone);
            Console.WriteLine("Do I Have Telephone Capabilities? {0}", smartphone is ITelephone);
            Console.WriteLine("Do I Have MP3 Capabilities?       {0}", smartphone is IMediaPlayer3);
    
            Console.ReadKey();
        }
    
        public interface IDevice
        {
            string Name { get; }
        }
    
        public interface ITelephone : IDevice
        {
            void OutboundCall(string number);
        }
    
        public interface IMediaPlayer3 : IDevice
        {
            void PlaySong(string filename);
        }
    
    
        public class Telephone : ITelephone
        {
            public string Name { get { return "Telephone"; } }
    
            public void OutboundCall(string number)
            {
                Console.WriteLine("Calling {0}", number);
            }
        }
    
        public class MediaPlayer3 : IMediaPlayer3
        {
            public string Name { get { return "MP3"; } }
    
            public void PlaySong(string filename)
            {
                Console.WriteLine("Playing Song {0}", filename);
            }
        }
    
        public class Smartphone : ITelephone, IMediaPlayer3
        {
            private readonly Telephone telephone;
            private readonly MediaPlayer3 mp3;
    
            public Smartphone()
            {
                telephone = new Telephone();
                mp3 = new MediaPlayer3();
            }
    
            public string Name { get { return "Smartphone"; } }
    
            public void OutboundCall(string number)
            {
                telephone.OutboundCall(number);
            }
    
            public void PlaySong(string filename)
            {
                mp3.PlaySong(filename);
            }
        }
    
    }
    

    节目输出:

    Telephone
    Calling +1 234 567
    Am I a Telephone?                 True
    Am I a MP3?                       False
    AM I a Smartphone?                False
    Do I Have Telephone Capabilities? True
    Do I Have MP3 Capabilities?       False
    
    MP3
    Playing Song Lalala
    Am I a Telephone?                 False
    Am I a MP3?                       True
    AM I a Smartphone?                False
    Do I Have Telephone Capabilities? False
    Do I Have MP3 Capabilities?       True
    
    Smartphone
    Calling +1 234 567
    Playing Song Lalala
    Am I a Telephone?                 False
    Am I a MP3?                       False
    AM I a Smartphone?                True
    Do I Have Telephone Capabilities? True
    Do I Have MP3 Capabilities?       True
    

    2023-01-07 09:32 回答
  • 您也可以使用显式接口实现来限制共享变量的使用Name.这样你就必须转向界面才能访问它.您仍然可以从界面获得公共属性/方法.

    仍然使用组合,但是SmartPhone可以控制其属性/方法的实现.

    对我来说,这将是一起工作的最简单的实现,因为我很少想使用这两种从MP3播放器及手机执行,但他们中的相当一个.此外,我仍然可以完全控制在调用接口方法时发生的情况SmartPhone.

    class User
    {
        void UseSmartPhone(SmartPhone smartPhone)
        {
            // Cannot access private property 'Name' here
            Console.WriteLine(smartPhone.Name);
    
            // Cannot access explicit implementation of 'IMp3Player.Play'
            smartPhone.Play();
    
            // You can send the phone to the method that accepts an IMp3Player though
            PlaySong(smartPhone);
    
            // This works fine. You are sure to get the Phone name here.
            Console.WriteLine(((IPhone)smartPhone).Name);
    
            // This works fine, since the Call is public in SmartPhone.
            smartPhone.Call();
        }
    
        void CallSomeone(IPhone phone)
        {
            phone.Call();
        }
    
        void PlaySong(IMp3Player player)
        {
            player.Play();
        }
    }
    
    class SmartPhone : IPhone, IMp3Player
    {
        private Phone mPhone;
        private Mp3Player mMp3Player;
    
        public SmartPhone()
        {
            mPhone = new Phone();
            mMp3Player = new Mp3Player();
        }
    
        public void Call()
        {
            mPhone.Call();
        }
    
        string IPhone.Name
        {
            get { return mPhone.Name; }
        }
    
        string IMp3Player.Name
        {
            get { return mMp3Player.Name; }
        }
    
        void IMp3Player.Play()
        {
            mMp3Player.Play();
        }
    }
    
    class Mp3Player
    {
        public string Name { get; set; }
    
        public void Play()
        {
        }
    }
    
    class Phone
    {
        public string Name { get; set; }
    
        public void Call()
        {
        }
    }
    
    interface IPhone
    {
        string Name { get; }
        void Call();
    }
    
    interface IMp3Player
    {
        string Name { get; }
        void Play();
    }
    

    2023-01-07 09:32 回答
  • 由于C#不支持多重继承,因此请考虑使用接口:

    public interface Phone{ ... }
    public interface Mp3{ ... }
    
    public class Telephone : Phone{ ... }
    public class Mp3Player : Mp3{ ... }
    public class Smartphone : Phone, Mp3{ ... }
    

    这种方式SmartphonePhoneMp3.如果您需要编写一个对a进行操作的方法Telephone,请改用该Phone接口.这样你就可以传递任何一个TelephoneSmartphone作为一个参数.

    2023-01-07 09:33 回答
  • 我认为这个面试问题不是(应该是所有面试问题)关于挑战本身.通过作文合并两个班级的编码练习可以用教科书来回答.这个挑战是一个微妙的技巧问题,我建议重点是让你讨论原因.至少这是我想从受访者那里得到的.


    这个测试:

    if(telMp3 is Telephone && telMp3 is MP3) {
    

    ......是真正的问题.你为什么必须符合这个标准?该测试完全阻止了从构图中构建对象的目的.它要求以特定方式实现对象.它表明现有的类实现已经与代码库紧密耦合(如果它们无法完成).这些要求意味着没有遵循SOLID原则,因为您不能只实现基类型的方法,您必须实际上基类型.那不好.


    正如其他答案所说,解决方案是使用接口.然后,您可以将对象传递给任何需要该接口的方法.这种用法需要像这样的测试:

    if (telMp3 is IPhone && telMp3 is IMp3) {
    

    ......但由于挑战的局限性,你无法做到这一点.这意味着在其余的代码中,人们一直在编写明确依赖于特定类型Telephone和方法的方法MP3.这是真正的问题.


    在我看来,这个挑战的正确答案是说代码库未通过测试.挑战中的具体影响是不可避免的; 在正确解决之前,您需要更改挑战的要求.一个认识到这个事实的受访者会通过测试,并且有很多颜色.

    2023-01-07 09:35 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有