2017-01-11 71 views
1

我有两个类,SensorChannel。通过在通道中“插入”传感器来使用它们(即,使用Sensor实例将Channel的属性设置为Sensor)。然后,当你调用AddSamplesChannel与非空传感器的Sensor.WhenNewSamples用户会被告知:使方法只能访问其他类

public abstract class Channel 
{ 
    public Sensor Sensor { get; set; } 

    public abstract void AddSamples(IEnumerable<double> samples) 
} 

public abstract class Sensor 
{ 
    public abstract IObservable<double> WhenNewSamples { get; } 

    internal abstract void AddSamples(IEnumerable<double> samples); 
} 

我想达成什么是内部传递这些样品的方式,而无需创建一个暴露Sensor.AddSamples。另外,当然,它应该与其他程序集中定义的子类一起工作,因为SensorChannel是抽象的,并且在域模型库中进行了定义。

UPDATE:

下执行就可以了,但它并不能编译,因为Sensor.AddSamples是内部和派生类在其他组件:

public class ConcreteChannel : Channel 
{ 
    public override void AddSamples(IEnumerable<double> samples) 
    { 
     // AddSamples below is inaccessible 
     Sensor.AddSamples(samples); 
    } 
} 

public class ConcreteSensor : Sensor 
{ 
    Subject<double> _subject = new Subject<double>(); 

    public override IObservable<double> WhenNewSamples 
    { 
     get { return _subject.AsObservable(); } 
    } 

    // "No suitable method found to override" 
    internal override void AddSamples(IEnumerable<double> samples) 
    { 
     samples.ToList().ForEach(s => _subject.OnNext(s)); 
    } 
} 
+1

使'AddSamples'受保护?然后它只能派生类才可见。或者我明白你是谁? – HimBromBeere

+0

@HimBromBeere我想'Channel.AddSamples'是公开的,但我不知道如何封装数据从'Channel'传递到'Channel.Sensor'而不创建一个公共的'Sensor.AddSamples',我会喜欢避免。我正在寻找一种“魔术隧道”,我只能在一个类中添加样本,并且它会在另一个类中弹出,前提是它们彼此“连接”(即Channel.Sensor属性被设置为“Sensor”的一个实例)。查看我的更新。 – heltonbiker

+0

如果您需要从课堂和大会以外的成员访问,那么它应该是“公开”的。没有办法绕过这个。 – HimBromBeere

回答

0

你可以使用嵌套类的能力访问父母的私有/ protected成员类:

abstract class A 
{ 
    protected abstract void SomeMethod(); 
} 
abstract class B { } 

class AA : A 
{ 
    public class BB : B 
    { 
     public void Test(AA a) => a.SomeMethod(); // no problem to access it here 
    } 
    protected override void SomeMethod() { } // is not public 
} 
+0

如果我理解正确,这将倒转遏制关系。例如,如果我想让BB访问AA.Method,那么BB需要在AA内?因为目前我有AA是BB的财产。我有点困惑(虽然我现在要试一试)。 – heltonbiker

1

我得到f igured,我被委派了太多的实现细节的子类,所以一个可能的解决方案是使用模板方法设计模式,采用合作三种不同的方法:

  • 一是模板方法:一个受保护的抽象应该由子类充实的方法;
  • 其他是实现“业务逻辑”的内部非虚拟方法:从内部方法调用到受保护的模板方法;
  • 某些“外部”类中的公共方法,将调用转发给“内部”类中的内部方法。

这样,得到以下调用堆栈:

  1. 我请在客户端组件限定的外子类的公共方法;
  2. 该方法实际上在核心程序集的基类中实现,并在核心程序集中也从内部基类中调用内部方法;
  3. 客户端基类中的内部方法调用受保护模板方法,该方法由客户端程序集中的内部子类实现。

我测试和它的作品,所以这里是德codez:

核心组件:

public abstract class Channel 
{ 
    // inner class is a property of outer class 
    public Sensor Sensor { get; set; } 

    // Public method in outer class calls internal method in inner class 
    public void AddSamples(IEnumerable<double> samples) 
    { 
     Sensor?.AddSamplesInternal(samples); 
    } 
} 

public abstract class Sensor 
{ 
    // domain specific property exposing the effects of template method 
    public abstract IObservable<double> WhenNewSamples { get; } 

    // internal method forwards the call to a protected abstract "template" method 
    internal void AddSamplesInternal(IEnumerable<double> samples) 
    { 
     AddSamplesProtected(samples); 
    } 

    // protected abstract method to be implemented by subclasses 
    protected abstract void AddSamplesProtected(IEnumerable<double> samples); 
} 

客户端组件:

using System.Linq; 
using System.Reactive.Linq; 
using System.Reactive.Subjects; 

public class ConcreteChannel : Channel 
{ 
    // no need to do anything - public method defined in base class 
} 

public class ConcreteSensor : Sensor 
{ 
    // domain specific implementation 
    public override IObservable<double> WhenNewSamples 
    { 
     get { return _subject.AsObservable(); } 
    } 
    Subject<double> _subject = new Subject<double>(); 

    // template method implemented locally, but called from business logic present in core lib 
    protected override void AddSamplesProtected(IEnumerable<double> samples) 
    { 
     samples.ToList().ForEach(sample => _subject.OnNext(sample)); 
    } 
} 

样例程序:

class Program 
{ 
    static void Main(string[] args) 
    { 
     ConcreteChannel channel = new ConcreteChannel(); 
     ConcreteSensor sensor = new ConcreteSensor(); 

     // "plugging" a sensor into a channel 
     channel.Sensor = sensor; 

     // "sensor" works as a data source for other client code 
     sensor.WhenNewSamples.Subscribe(Console.WriteLine); 

     // channel works as a data target for data coming from some server class 
     channel.AddSamples(Enumerable.Range(0, 10).Select(Convert.ToDouble)); 
    } 
} 

输出:

0 
1 
2 
3 
4 
5 
6 
7 
8 
9