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

面向对象,接口设计和封装[关闭]

  •  1
  • Mau  · 技术社区  · 14 年前

    public interface IPublicData {}
    
    public /* internal */ interface IInternalDataProducer { string GetData(); }
    
    public interface IPublicWorker {
        IPublicData DoWork();
        IInternalDataProducer GetInternalProducer();
    }
    
    public class Engine {
        Engine(IPublicWorker worker) {}
        IPublicData Run() {
            DoSomethingWith(worker.GetInternalProducer().GetData());
            return worker.DoWork();
        }
    }
    

    Engine 在实际工作人员中是参数化的。参数化的另一个来源是我们如何通过 IInternalDataProducer 内部数据生产者 IPublicWorker . 不过,我希望它是内部的,因为它只用于发动机。

    解决办法是 IPublicWorker公司 生成内部数据本身,但这并不是很优雅,因为只有几种方法可以生成它(同时还有更多的worker实现),因此最好将它委托给两个单独的具体类。而且 内部数据生产者

    显然,也没有一个选项是传递 内部数据生产者 直接到 发动机

    我在寻找优雅的,类型安全的,想法/模式。 干杯:-)

    编辑:根据杰夫的回答,这里有一个解决方案:

    GetData() 用户不需要看到它(但我原来的界面也很脏),因为它会导致“界面重复”( 获取数据() 是在2个接口中声明的)-你不可能拥有所有的东西。

    下一个问题是如何清洁 获取数据() 在外面

    public interface IPublicData {}
    
    internal /* ! */ interface IInternalDataProducer { string GetData(); }
    
    public interface IPublicWorker {
        IPublicData DoWork();
        string GetData();
    }
    
    public class APublicWorker : IPublicWorker {
    
        private IInternalDataProducer dataProducer;
    
        public APublicWorker() {
            dataProducer = new SomeDataProducer();
        }
    
        IPublicData DoWork() { ... }
        string GetData() {
            /* Delegation! */
            return dataProducer.GetData();
            /* ********* */
        }
    }
    
    public class Engine {
        Engine(IPublicWorker worker) {}
        IPublicData Run() {
            DoSomethingWith(worker.GetData());
            return worker.DoWork();
        }
    }
    
    5 回复  |  直到 14 年前
        1
  •  0
  •   Jeff Sternal    14 年前

    您可以通过将数据生产者封装在worker中来解决此问题:

    public interface IPublicWorker {
        IPublicData DoWork();
        // Callers don't care how a worker gets this data
        string GetData();
    }
    

    调用引擎如下所示:

    IPublicData Run() {
        DoSomethingWith(worker.GetData());
        return worker.DoWork();
    }
    
        2
  •  0
  •   jeroenh    14 年前

    实际上,奥列格的解决方案并不是那么糟糕,但是可以改进。

    考虑到您希望对IPPublicWorker接口施加限制,我假设您希望控制IPPublicWorker的实现,并为用户提供特定的API来获取这些接口。如果是这样,您可以从IPPublicWorker派生IIInternalPublicWorker,并在引擎的构造函数中,验证IPPublicWorker确实是预期类型:

    public interface IPublicData {}
    
    
    public internal interface IInternalDataProducer { string GetData(); }
    
    public interface IPublicWorker {
        IPublicData DoWork();
    }
    
    public internal interface IInternalPublicWorker : IPublicWorker {
        IInternalDataProducer GetInternalProducer();
    }
    
    public class Engine 
    {
        IInternalPublicWorker _worker;
    
        Engine(IPublicWorker worker) 
        { 
            if (!(worker is IInternalPublicWorker)) 
            {
               throw new InvalidOperationException("We don't support workers that were not obtained from our library."); // add some helpful message about which method to use to obtain a worker
            }
            _worker = (IInternalPublicWorker)worker;
        }
        IPublicData Run() 
        {
            DoSomethingWith(_worker.GetInternalProducer().GetData());
            return _worker.DoWork();
        }
    }
    
        3
  •  0
  •   Morfildur    14 年前

    更新
    我的解决方案似乎不正确,至少它没有像我想的那样起作用。也许其他人可以让它工作,因为它将是(imho)最合乎逻辑的解决方案。


    public interface IPublicData {}
    
    public interface IPublicDataProducer {}
    internal interface IInternalDataProducer : IPublicDataProducer { string GetData(); }
    
    public interface IPublicWorker {
        IPublicData DoWork();
        IPublicDataProducer GetProducer();
    }
    
    public class Engine {
        Engine(IPublicWorker worker) {}
        IPublicData Run() {
            DoSomethingWith(worker.GetProducer());
            return worker.DoWork();
        }
    }
    

    这允许您分离接口的外部和内部用户的数据。

        4
  •  0
  •   Restuta    14 年前

    编辑

    public interface IPublicData { }
    
    public interface IDataProducer { string GetData(); }
    
    internal interface IInternalDataProducer : IDataProducer { string GetData(); }
    
    internal class InternalDataProducer : IInternalDataProducer
    {
        public string GetData()
        {
            throw new NotImplementedException();
        }
    }
    
    public interface IPublicWorker
    {
        IPublicData DoWork();
        IDataProducer GetInternalProducer();
    }
    
    class PublicWorker : IPublicWorker
    {
        public IPublicData DoWork()
        {
            throw new NotImplementedException();
        }
    
        public IDataProducer GetInternalProducer()
        {
            return new InternalDataProducer(); //here you binds PublicWorker to paricular data provider
        }
    }
    
    
    public class Engine
    {
        private IPublicWorker worker;
    
        public Engine(IPublicWorker worker)
        {
            this.worker = worker;
        }
    
        IPublicData Run()
        {
            DoSomethingWith(this.worker.GetInternalProducer());
            return worker.DoWork();
        }
    
        private void DoSomethingWith(IDataProducer getData)
        {
            throw new NotImplementedException();
        }
    }
    
        5
  •  -2
  •   Oleg Zhylin    14 年前

    为什么不将GetInternalProducer()定义为

      object GetInternalProducer();
    

       IInternalDataProducer producer = GetInternalProducer() as IInternalDataProducer.
    

    您必须检查空指针,但不需要再公开IInternalDataProducer。