Controlling read/write access to fields

2019-06-06 12:53发布

Suppose that we would like to separate out the read and write access in an interface pattern as below.

namespace accesspattern
{
    namespace ReadOnly
    {
        public interface IA { double get_a(); }
    }
    namespace Writable
    {
        public interface IA : ReadOnly.IA { void set_a(double value); }
    }
}

This is easy to implement:

namespace accesspattern
{
    namespace ReadOnly
    {
        public class A : IA
        {
            protected double a;
            public double get_a() { return a; }
        }
    }
    namespace Writable
    {
        public class A : ReadOnly.A, IA
        {
            public void set_a(double value) { base.a = value; }
        }

    }
}

Suppose that we need another class which inherits from A and so we go ahead and define an interface for it:

namespace accesspattern
{
    namespace ReadOnly
    {
        public interface IB : ReadOnly.IA { int get_b(); }

    }
    namespace Writable
    {
        public interface IB : ReadOnly.IB, Writable.IA { void set_b(int value); }
    }
}

Implementing this is not so easy. One always feels that Writable.B should inherit from two base classes, Writable.A and ReadOnly.B, to avoid repeated code.

Is there a recommended Design Pattern to use? The aim is to be able to return "read access only" and "read write access" objects separately (decided at compile time) depending on requirements. It would be nice if the solution pattern makes it easy to add more layers of inheritance, classes C, D...

I know that the issue of Multiple Inheritance crops up here and that it has been discussed at length elsewhere in many, many, places. But my question is not so much "How to implement the interfaces which are defined inside the namespace accesspattern without using multiple inheritance" (although I would like to learn the best way to do that) but rather, how can we define the ReadOnly/Writable versions of a class separately and also support inheritance without it getting very, very, messy?

For what it is worth here is one (messy) solution [see below for much a better implementation]:

    namespace accesspattern
    {
        namespace ReadOnly
        {
            public class A : IA
            {
                protected double a;
                public double get_a() { return a; }
            }
            public class B : IB
            {
                protected int b;
                public int get_b() { return b; }
            }
        }
        namespace Writable
        {
            public class A : ReadOnly.A, IA
            {
                public void set_a(double value) { base.a = value; }
            }
            public class B : ReadOnly.B, IB
            {
                private IA aObj;
                public double get_a() { return aObj.get_a(); }
                public void set_a(double value) { aObj.set_a(value); }
                public void set_b(int value) { base.b = value; }
                public B() { aObj = new A(); }
            }
        }
    }
}

Update: I think that this (below) is what Eugene is talking about. This implementation pattern is pretty good, I think. By only passing around "writeProtected" views of classes one can implement algorithms which require that the state of the class will not change and only use "writeEnabled" views where it is meant that the function will/could cause a change in state avoiding.

namespace access
{

    // usual usage is at least readable
    public interface IA { double get_a(); }
    public interface IB : IA { int get_b(); }

    // special usage is writable as well
    namespace writable
    {
        public interface IA : access.IA { void set_a(double value);  }
        public interface IB : access.IB, IA { void set_b(int value);}
    }

    // Implement the whole of A in one place
    public class A : writable.IA
    {
        private double a;
        public double get_a() { return a; }
        public void set_a(double value) { a = value; }
        public A() { }

        //support write-protection
        public static IA writeProtected() { return new A(); }
        public static writable.IA writable() { return new A(); }
    }
    // implement the whole of B in one place and now no issue with using A as a base class
    public class B : A, writable.IB
    {
        private int b;
        public double get_b() { return b; }
        public void set_b(int value) { b = value; }
        public B() : base() { }

        // support write protection 
        public static IB writeProtected() { return new B(); }
        public static writable.IB writable() { return new B(); }
    }

    public static class Test
    {
        static void doSomething(IA a)
        {
            // a is read-only
        }
        static void alterState(writable.IB b)
        {
            // b is writable
        }
        static void example()
        {
            // Write protected
            IA a = access.A.writeProtected();
            IB b = access.B.writeProtected();

            // write enabled
            writable.IA A = access.A.writable();
            writable.IB B = access.B.writable();

            Console.WriteLine(a.get_a());
            B.set_b(68);

            doSomething(A); // passed as writeprotected
            alterState(B); // passed as writable
        }
    }
}

2条回答
The star\"
2楼-- · 2019-06-06 13:40

I know this thread is one year old, but I'm wondering if it would make sense to have something like this:

 interface ReadOnlyA
 {
    object A { get; }
 }

 interface WriteableA : ReadOnlyA
 {
   new object A {get; set;}
 }
查看更多
女痞
3楼-- · 2019-06-06 13:54

You can provide the read/write access at Service level and not at Entity level. In that case you can code generate a wrapper around services that handles the read/write access. Patterns used: Decorator, Dependency Injection

查看更多
登录 后发表回答