简体   繁体   中英

Abstract classes C#

I have an interface

using ClassAbstractFactory;
public interface IPlugin
{
    AbstractFactory GetFactory();  
}

and an AbstractFactory

public abstract class AbstractFactory
{
    public abstract AbstractCake CreateCake();
    public abstract AbstractBox CreateBox();
}

public abstract class AbstractCake
{

    public abstract void Interact(AbstractBox box);

}

public abstract class AbstractBox
{

}

and I have .dll that inherit AbstractCake

 public class ChocolateCake : AbstractCake
{

    private bool _isPacked;
    private bool _isDecorated;
    private string _nameOfCake;

    public ChocolateCake()
    {
        _isPacked = false;
        _isDecorated = false;
        _nameOfCake = "Шоколадный";
    }


   public bool IsPacked
   {
        get { return _isPacked; }
   }

    public bool IsDecorated
    {
        get { return _isDecorated; }

    }

    public string NameOfCake { get; set; }


    public override void Interact(AbstractBox box)
    {     
            _isPacked = true;       
    }


}

I load dll like this:

 public IPlugin LoadAssembly(string assemblyPath)
    {
        Assembly ptrAssembly = Assembly.LoadFile(assemblyPath);

        foreach (Type item in ptrAssembly.GetTypes())
        {
            if (!item.IsClass) continue;
            if (item.GetInterfaces().Contains(typeof(IPlugin)))
            {
                return (IPlugin)Activator.CreateInstance(item);
            }
        }
        throw new Exception("Invalid DLL, Interface not found!");
    }

        List<IPlugin> list = new List<IPlugin>();
        foreach (var assemblyPath in GetPathsListToDll())
        {
            list.Add(LoadAssembly(assemblyPath));
        }

How can I acess to attributes in my ChocolateCake,to use them like

foreach (var str in list)
        {
            Boolean a = str.GetFactory().GetCake().CreateCake().IsPacked;
        }

or like this

string a = str.GetFactory().GetCake().CreateCake().NameOfCake;

or like this

str.GetFactory().GetCake().CreateCake().NameOfCake("Something");

or like this

str.GetFactory().GetCake().CreateCake().IsDecorated(true);

The problem here is that the AbstractFactory has a method that returns AbstractCake , and AbstractCake itself has no properties at all. As it stands, you would need to downcast the Cake (direct, or with the as keyword) to a ChocolateCake prior to accessing any of its properties, which is really messy:

string a = (ChocolateCake)(str.GetFactory().CreateCake()).NameOfCake;

Here are some considerations:

  1. Move the properties which are common to all types of cake into AbstractCake , eg NameOfCake , IsPacked and IsDecorated
  2. Given that the AbstractFactory and AbstractCake classes do not have any implementation at all, consider changing these to interfaces instead of abstract classes, ie ICakeFactory and ICake . Concrete implementations will be ChocolateCakeFactory and ChocolateCake as before.
  3. Consumers of the factory and the cake should now only access what is exposed on the interfaces ( ICakeFactory , ICake and IBox ), and not need to do any down casting or make any assumptions about the actual concrete type of Cake etc.

ie

public interface ICake
{
    void Interact(IBox box);
    bool IsPacked { get; }
    bool IsDecorated { get; }
    string NameOfCake { get; set; }
}

public class ChocolateCake : ICake
{
    private bool _isPacked;
    private bool _isDecorated;
    private string _nameOfCake;

    public ChocolateCake() // ctor is not on the interface and is implementation detail
    {
        _isPacked = false;
        _isDecorated = false;
        _nameOfCake = "Шоколадный";
    }       

    public void Interact(IBox box) {...}
    public bool IsPacked { get { return _isPacked; } }
    public bool IsDecorated { get { return _isDecorated; } }
    // ...
}

public interface ICakeFactory
{
    ICake CreateCake();
    IBox CreateBox();
}

public class ChocolateCakeFactory : ICakeFactory
{
    public ICake CreateCake()   {return new ChocolateCake();}
    public IBox CreateBox() {return new ChocolateCakeBox();} 
}

Re : Usage

It is highly unlikely that you would ever do this:

string a = str.GetFactory().GetCake().CreateCake().NameOfCake;
str.GetFactory().GetCake().CreateCake().NameOfCake = "Something"; // Prop setter

as this would create a new cake instance each time (and discard the instance). How about:

class Bakery
{
   private readonly ICakeFactory _cakeFactory;
   public Bakery(ICakeFactory cakeFactory)
   {
       Contract.Requires(cakeFactory != null);
       cakeFactory = _cakeFactory;
   }

   bool BakeStuff()
   {
       var cake = _cakeFactory.CreateCake();
       cake.NameOfCake = "StackOverflow";
       return cake.IsDecorated && cake.IsPacked;
   }
}

Edit, Re Raise change Events

This involves implementing INotifyPropertyChanged

public interface ICake : INotifyPropertyChanged

Which you can then raise on your mutable properties, eg

public string NameOfCake
{
    get { return _nameOfCake} ;
    set { 
        var propChanged = PropertyChanged;
        if (propChanged != null && value != _nameOfCake)
        {
            propChanged(this, new PropertyChangedEventArgs("NameOfCake"));
        }
        _nameOfCake = value;
    }
}

And subscribe like so

var cake = new ChocolateCake();
cake.PropertyChanged += (sender, eventArgs) 
     => Console.WriteLine("Property {0} has changed", eventArgs.PropertyName);

Would this work?

public abstract class AbstractFactory
{
    public abstract TCake CreateCake<TCake>() where TCake : AbstractCake, new();
    public abstract AbstractBox CreateBox();
}

...

var cake = str.GetFactory().CreateCake<ChocolateCake>();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM