In this MSDN Magazine article Peter Vogel describes Extension Objects pattern.
What is not clear is whether extensions can be later implemented by client code residing in a separate assembly.
And if so how in this case can extension get access to private members of the object being extended?
I quite often need to set different access levels for different classes.
Sometimes I really need that descendants does not have access to the member but separate class does. (good old friend classes)
Now I solve this in C# by exposing callback properties in interface of the external class and setting them with private methods. This also allows to adjust access: read only or read|write depending on the desired interface.
class Parent
{
private int foo;
public void AcceptExternal(IFoo external)
{
external.GetFooCallback = () => this.foo;
}
}
interface IFoo
{
Func<int> GetFooCallback {get;set;}
}
Other way is to explicitly implement particular interface.
But I suspect more aspproaches exist.
Update 1
New Peter's article makes it a bit clearer.
-
This sounds like you should rethink your design.svick– svick2013年04月27日 09:07:07 +00:00Commented Apr 27, 2013 at 9:07
-
Sounds what? The question is how Roles pattern should be implemented when extension needs access to private part of the class. Do you mean that extansible part must be publicly visible?Pavel Voronin– Pavel Voronin2013年04月28日 08:45:03 +00:00Commented Apr 28, 2013 at 8:45
-
A proxy pattern. pg 207 from the GoF book if you want more detail.JustinC– JustinC2013年06月27日 05:25:22 +00:00Commented Jun 27, 2013 at 5:25
1 Answer 1
I think that you missed a little bit of the point of the article. When he was talking about think in the Extension, he was talking about an concept, and not a particular Design Pattern. There are several Design Patterns that would allow for extension of your objects, this really depends on how you want to do it. Let me quote what 2 think could be the best to allow for extension:
Decorator Pattern:
private interface IPrice
{
int Price { get; }
}
private class PriceDecorator : Pizza
{
IPrice _price;
protected virtual int OriginalPrice { get { return 0; } }
public virtual int Price
{
get { return OriginalPrice + _price.Price; }
}
protected PriceDecorator() { }
public PriceDecorator(IPrice price)
: this()
{
_price = price;
}
}
private class Pizza : PriceDecorator
{
public Pizza(IPrice price) : base(price){}
protected Pizza() { }
protected override int OriginalPrice
{
get { return 10; }
}
}
class Cheese : PriceDecorator
{
protected Cheese() { }
public Cheese(IPrice price) : base(price) { }
protected override int OriginalPrice
{
get { return 2; }
}
}
class Pepperoni : PriceDecorator
{
protected Pepperoni() {}
public Pepperoni(IPrice price) : base(price){ }
protected override int OriginalPrice
{
get { return 1; }
}
}
class test
{
void run()
{
var pizzaWithCheese = new Pizza(new Cheese());
var pizzaWithCheeseAndPepperoni = new Pizza(new Cheese(new Pepperoni()));
}
}
Strategy Design Pattern:
You can read more here
abstract class StrategyBase
{
public abstract void DoSomething();
}
class ConcreteStrategyA : StrategyBase
{
public override void DoSomething()
{
Console.WriteLine("Called ConcreteStrategyA.DoSomething()");
}
}
class ConcreteStrategyB : StrategyBase
{
public override void DoSomething()
{
Console.WriteLine("I did something!");
}
}
/// This is the class that you allow extension, using any of the strategies
class Context
{
private StrategyBase _strategy;
public Context(StrategyBase strategy)
{
this._strategy = strategy;
}
public void DoSomething()
{
_strategy.DoSomething();
}
}
// Use it like this:
var c = new Context(new ConcreteStrategyA());
c.DoSomething();
-
1The article contains link to this pattern: mif.vu.lt/~plukas/resources/Extension%20Objects/… The idea is clear, but the implementation is vague. At least for me. Quite often role need access to private members.Pavel Voronin– Pavel Voronin2013年06月26日 21:58:41 +00:00Commented Jun 26, 2013 at 21:58